From b0cc82fc050d6194661fc92ca67407066d65b603 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Mon, 9 Sep 2024 08:02:11 +0000 Subject: [PATCH] [1 changes] fix(mem2reg): Handle aliases in function last store cleanup and additional alias unit test (https://github.com/noir-lang/noir/pull/5967) fix: let `derive(Eq)` work for empty structs (https://github.com/noir-lang/noir/pull/5965) feat: add `FunctionDefinition` methods `is_unconstrained` and `set_unconstrained` (https://github.com/noir-lang/noir/pull/5962) feat: LSP autocompletion for attributes (https://github.com/noir-lang/noir/pull/5963) feat: `Module::add_item` (https://github.com/noir-lang/noir/pull/5947) feat: Add `StructDefinition::add_generic` (https://github.com/noir-lang/noir/pull/5961) feat: Add `StructDefinition::name` (https://github.com/noir-lang/noir/pull/5960) fix(mem2reg): Handle aliases better when setting a known value for a load (https://github.com/noir-lang/noir/pull/5959) feat: Arithmetic Generics (https://github.com/noir-lang/noir/pull/5950) feat: add `FunctionDefinition::module` and `StructDefinition::module` (https://github.com/noir-lang/noir/pull/5956) feat: LSP now suggests self fields and methods (https://github.com/noir-lang/noir/pull/5955) --- .noir-sync-commit | 2 +- noir/noir-repo/.gitattributes | 1 - noir/noir-repo/acvm-repo/acvm_js/build.sh | 2 +- .../aztec_macros/src/utils/hir_utils.rs | 4 +- .../compiler/noirc_driver/src/lib.rs | 5 - .../noirc_evaluator/src/ssa/opt/mem2reg.rs | 115 +++- .../compiler/noirc_frontend/src/ast/mod.rs | 1 + .../noirc_frontend/src/ast/visitor.rs | 55 +- .../noirc_frontend/src/elaborator/comptime.rs | 128 +++- .../noirc_frontend/src/elaborator/lints.rs | 87 +-- .../noirc_frontend/src/elaborator/mod.rs | 65 +- .../noirc_frontend/src/elaborator/types.rs | 11 +- .../noirc_frontend/src/hir/comptime/errors.rs | 49 +- .../src/hir/comptime/interpreter.rs | 22 +- .../src/hir/comptime/interpreter/builtin.rs | 460 +++++++++++--- .../interpreter/builtin/builtin_helpers.rs | 31 + .../noirc_frontend/src/hir/comptime/tests.rs | 2 +- .../noirc_frontend/src/hir/comptime/value.rs | 10 +- .../src/hir/def_collector/dc_crate.rs | 11 +- .../noirc_frontend/src/hir/def_map/mod.rs | 2 - .../noirc_frontend/src/hir_def/types.rs | 10 +- .../compiler/noirc_frontend/src/parser/mod.rs | 3 +- .../noirc_frontend/src/parser/parser.rs | 18 +- .../src/parser/parser/function.rs | 28 +- .../src/parser/parser/visibility.rs | 15 +- .../compiler/noirc_frontend/src/tests.rs | 35 +- .../docs/docs/noir/concepts/generics.md | 59 +- .../standard_library/meta/function_def.md | 36 ++ .../docs/noir/standard_library/meta/module.md | 8 + .../docs/noir/standard_library/meta/quoted.md | 6 + .../noir/standard_library/meta/struct_def.md | 45 ++ .../docs/noir/standard_library/meta/typ.md | 24 + noir/noir-repo/noir_stdlib/src/cmp.nr | 8 +- .../noir_stdlib/src/meta/function_def.nr | 25 + noir/noir-repo/noir_stdlib/src/meta/module.nr | 5 + noir/noir-repo/noir_stdlib/src/meta/quoted.nr | 13 +- .../noir_stdlib/src/meta/struct_def.nr | 31 +- noir/noir-repo/noir_stdlib/src/meta/typ.nr | 5 + .../Nargo.toml | 7 + .../src/main.nr | 32 + .../arithmetic_generics_underflow/Nargo.toml | 7 + .../arithmetic_generics_underflow/src/main.nr | 14 + .../attributes_struct/src/main.nr | 13 + .../comptime_function_definition/src/main.nr | 31 +- .../comptime_module/src/main.nr | 33 +- .../Nargo.toml | 2 +- .../comptime_struct_definition/src/main.nr | 50 ++ .../comptime_type/src/main.nr | 35 ++ .../comptime_type_definition/src/main.nr | 26 - .../references_aliasing/src/main.nr | 13 + .../execution_success/derive/src/main.nr | 6 + .../verify_honk_proof/Nargo.toml | 6 - .../verify_honk_proof/Prover.toml | 575 ------------------ .../verify_honk_proof/src/main.nr | 17 - .../tooling/lsp/src/requests/completion.rs | 153 ++++- .../lsp/src/requests/completion/builtins.rs | 38 +- .../requests/completion/completion_items.rs | 72 ++- .../lsp/src/requests/completion/kinds.rs | 4 +- .../lsp/src/requests/completion/tests.rs | 68 ++- noir/noir-repo/tooling/nargo_cli/build.rs | 2 +- .../noir_js_backend_barretenberg/package.json | 2 +- .../noir-repo/tooling/noirc_abi_wasm/build.sh | 2 +- noir/noir-repo/yarn.lock | 13 +- 63 files changed, 1705 insertions(+), 953 deletions(-) delete mode 100644 noir/noir-repo/.gitattributes create mode 100644 noir/noir-repo/test_programs/compile_failure/arithmetic_generics_intermediate_underflow/Nargo.toml create mode 100644 noir/noir-repo/test_programs/compile_failure/arithmetic_generics_intermediate_underflow/src/main.nr create mode 100644 noir/noir-repo/test_programs/compile_failure/arithmetic_generics_underflow/Nargo.toml create mode 100644 noir/noir-repo/test_programs/compile_failure/arithmetic_generics_underflow/src/main.nr rename noir/noir-repo/test_programs/compile_success_empty/{comptime_type_definition => comptime_struct_definition}/Nargo.toml (69%) create mode 100644 noir/noir-repo/test_programs/compile_success_empty/comptime_struct_definition/src/main.nr delete mode 100644 noir/noir-repo/test_programs/compile_success_empty/comptime_type_definition/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 cfaf9d81cf2..160c7463cad 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -b84009ca428a5790acf53a6c027146b706170574 +36756e8757ad40e2b231747ed754273f50e5dc2f diff --git a/noir/noir-repo/.gitattributes b/noir/noir-repo/.gitattributes deleted file mode 100644 index 204cff5c097..00000000000 --- a/noir/noir-repo/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.nr linguist-language=rust 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/utils/hir_utils.rs b/noir/noir-repo/aztec_macros/src/utils/hir_utils.rs index 0a8ce371708..200ce3099cb 100644 --- a/noir/noir-repo/aztec_macros/src/utils/hir_utils.rs +++ b/noir/noir-repo/aztec_macros/src/utils/hir_utils.rs @@ -195,7 +195,7 @@ pub fn inject_fn( let trait_id = None; items.functions.push(UnresolvedFunctions { file_id, functions, trait_id, self_type: None }); - let mut errors = Elaborator::elaborate(context, *crate_id, items, None, false); + let mut errors = Elaborator::elaborate(context, *crate_id, items, None); errors.retain(|(error, _)| !CustomDiagnostic::from(error).is_warning()); if !errors.is_empty() { @@ -241,7 +241,7 @@ pub fn inject_global( let mut items = CollectedItems::default(); items.globals.push(UnresolvedGlobal { file_id, module_id, global_id, stmt_def: global }); - let _errors = Elaborator::elaborate(context, *crate_id, items, None, false); + let _errors = Elaborator::elaborate(context, *crate_id, items, None); } pub fn fully_qualified_note_path(context: &HirContext, note_id: StructId) -> Option { diff --git a/noir/noir-repo/compiler/noirc_driver/src/lib.rs b/noir/noir-repo/compiler/noirc_driver/src/lib.rs index a315e7ed397..31c279bc0f3 100644 --- a/noir/noir-repo/compiler/noirc_driver/src/lib.rs +++ b/noir/noir-repo/compiler/noirc_driver/src/lib.rs @@ -120,10 +120,6 @@ pub struct CompileOptions { #[arg(long, hide = true)] pub show_artifact_paths: bool, - /// Temporary flag to enable the experimental arithmetic generics feature - #[arg(long, hide = true)] - pub arithmetic_generics: bool, - /// Flag to turn off the compiler check for under constrained values. /// Warning: This can improve compilation speed but can also lead to correctness errors. /// This check should always be run on production code. @@ -289,7 +285,6 @@ pub fn check_crate( crate_id, context, options.debug_comptime_in_file.as_deref(), - options.arithmetic_generics, error_on_unused_imports, macros, ); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs index 89445c4d195..8c128c452d0 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs @@ -181,7 +181,12 @@ impl<'f> PerFunctionContext<'f> { self.last_loads.get(store_address).is_none() }; - if remove_load && !is_reference_param { + let is_reference_alias = block + .expressions + .get(store_address) + .map_or(false, |expression| matches!(expression, Expression::Dereference(_))); + + if remove_load && !is_reference_param && !is_reference_alias { self.instructions_to_remove.insert(*store_instruction); } } @@ -286,19 +291,19 @@ impl<'f> PerFunctionContext<'f> { } else { references.mark_value_used(address, self.inserter.function); - let expression = if let Some(expression) = references.expressions.get(&result) { - expression.clone() - } else { - references.expressions.insert(result, Expression::Other(result)); - Expression::Other(result) - }; - if let Some(aliases) = references.aliases.get_mut(&expression) { + let expression = + references.expressions.entry(result).or_insert(Expression::Other(result)); + // Make sure this load result is marked an alias to itself + if let Some(aliases) = references.aliases.get_mut(expression) { + // If we have an alias set, add to the set aliases.insert(result); } else { + // Otherwise, create a new alias set containing just the load result references .aliases .insert(Expression::Other(result), AliasSet::known(result)); } + // Mark that we know a load result is equivalent to the address of a load. references.set_known_value(result, address); self.last_loads.insert(address, (instruction, block_id)); @@ -789,4 +794,98 @@ mod tests { // We expect the last eq to be optimized out assert_eq!(b1_instructions.len(), 0); } + + #[test] + fn keep_store_to_alias_in_loop_block() { + // This test makes sure the instruction `store Field 2 at v5` in b2 remains after mem2reg. + // Although the only instruction on v5 is a lone store without any loads, + // v5 is an alias of the reference v0 which is stored in v2. + // This test makes sure that we are not inadvertently removing stores to aliases across blocks. + // + // acir(inline) fn main f0 { + // b0(): + // v0 = allocate + // store Field 0 at v0 + // v2 = allocate + // store v0 at v2 + // jmp b1(Field 0) + // b1(v3: Field): + // v4 = eq v3, Field 0 + // jmpif v4 then: b2, else: b3 + // b2(): + // v5 = load v2 + // store Field 2 at v5 + // v8 = add v3, Field 1 + // jmp b1(v8) + // b3(): + // v9 = load v0 + // v10 = eq v9, Field 2 + // constrain v9 == Field 2 + // v11 = load v2 + // v12 = load v10 + // v13 = eq v12, Field 2 + // constrain v11 == Field 2 + // return + // } + let main_id = Id::test_new(0); + let mut builder = FunctionBuilder::new("main".into(), main_id); + + let v0 = builder.insert_allocate(Type::field()); + let zero = builder.numeric_constant(0u128, Type::field()); + builder.insert_store(v0, zero); + + let v2 = builder.insert_allocate(Type::field()); + // Construct alias + builder.insert_store(v2, v0); + let v2_type = builder.current_function.dfg.type_of_value(v2); + assert!(builder.current_function.dfg.value_is_reference(v2)); + + let b1 = builder.insert_block(); + builder.terminate_with_jmp(b1, vec![zero]); + + // Loop header + builder.switch_to_block(b1); + let v3 = builder.add_block_parameter(b1, Type::field()); + let is_zero = builder.insert_binary(v3, BinaryOp::Eq, zero); + + let b2 = builder.insert_block(); + let b3 = builder.insert_block(); + builder.terminate_with_jmpif(is_zero, b2, b3); + + // Loop body + builder.switch_to_block(b2); + let v5 = builder.insert_load(v2, v2_type.clone()); + let two = builder.numeric_constant(2u128, Type::field()); + builder.insert_store(v5, two); + let one = builder.numeric_constant(1u128, Type::field()); + let v3_plus_one = builder.insert_binary(v3, BinaryOp::Add, one); + builder.terminate_with_jmp(b1, vec![v3_plus_one]); + + builder.switch_to_block(b3); + let v9 = builder.insert_load(v0, Type::field()); + let _ = builder.insert_binary(v9, BinaryOp::Eq, two); + + builder.insert_constrain(v9, two, None); + let v11 = builder.insert_load(v2, v2_type); + let v12 = builder.insert_load(v11, Type::field()); + let _ = builder.insert_binary(v12, BinaryOp::Eq, two); + + builder.insert_constrain(v11, two, None); + builder.terminate_with_return(vec![]); + + let ssa = builder.finish(); + + // We expect the same result as above. + let ssa = ssa.mem2reg(); + + let main = ssa.main(); + assert_eq!(main.reachable_blocks().len(), 4); + + // The store from the original SSA should remain + assert_eq!(count_stores(main.entry_block(), &main.dfg), 2); + assert_eq!(count_stores(b2, &main.dfg), 1); + + assert_eq!(count_loads(b2, &main.dfg), 1); + assert_eq!(count_loads(b3, &main.dfg), 3); + } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/mod.rs index 3fd63249201..1ed88115fa0 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/mod.rs @@ -12,6 +12,7 @@ mod traits; mod type_alias; mod visitor; +pub use visitor::AttributeTarget; pub use visitor::Visitor; pub use expression::*; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs index 0aeeed39dd0..64b479b5fd6 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs @@ -16,7 +16,7 @@ use crate::{ QuotedTypeId, }, parser::{Item, ItemKind, ParsedSubModule}, - token::{SecondaryAttribute, Tokens}, + token::{CustomAtrribute, SecondaryAttribute, Tokens}, ParsedModule, QuotedType, }; @@ -26,6 +26,13 @@ use super::{ UnresolvedTypeExpression, }; +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum AttributeTarget { + Module, + Struct, + Function, +} + /// Implements the [Visitor pattern](https://en.wikipedia.org/wiki/Visitor_pattern) for Noir's AST. /// /// In this implementation, methods must return a bool: @@ -433,7 +440,15 @@ pub trait Visitor { true } - fn visit_secondary_attribute(&mut self, _: &SecondaryAttribute, _: Span) {} + fn visit_secondary_attribute( + &mut self, + _: &SecondaryAttribute, + _target: AttributeTarget, + ) -> bool { + true + } + + fn visit_custom_attribute(&mut self, _: &CustomAtrribute, _target: AttributeTarget) {} } impl ParsedModule { @@ -484,7 +499,7 @@ impl Item { module_declaration.accept(self.span, visitor); } ItemKind::InnerAttribute(attribute) => { - attribute.accept(self.span, visitor); + attribute.accept(AttributeTarget::Module, visitor); } } } @@ -492,6 +507,10 @@ impl Item { impl ParsedSubModule { pub fn accept(&self, span: Span, visitor: &mut impl Visitor) { + for attribute in &self.outer_attributes { + attribute.accept(AttributeTarget::Module, visitor); + } + if visitor.visit_parsed_submodule(self, span) { self.accept_children(visitor); } @@ -510,6 +529,10 @@ impl NoirFunction { } pub fn accept_children(&self, visitor: &mut impl Visitor) { + for attribute in self.secondary_attributes() { + attribute.accept(AttributeTarget::Function, visitor); + } + for param in &self.def.parameters { param.typ.accept(visitor); } @@ -674,6 +697,10 @@ impl NoirStruct { } pub fn accept_children(&self, visitor: &mut impl Visitor) { + for attribute in &self.attributes { + attribute.accept(AttributeTarget::Struct, visitor); + } + for (_name, unresolved_type) in &self.fields { unresolved_type.accept(visitor); } @@ -694,6 +721,10 @@ impl NoirTypeAlias { impl ModuleDeclaration { pub fn accept(&self, span: Span, visitor: &mut impl Visitor) { + for attribute in &self.outer_attributes { + attribute.accept(AttributeTarget::Module, visitor); + } + visitor.visit_module_declaration(self, span); } } @@ -1295,8 +1326,22 @@ impl Pattern { } impl SecondaryAttribute { - pub fn accept(&self, span: Span, visitor: &mut impl Visitor) { - visitor.visit_secondary_attribute(self, span); + pub fn accept(&self, target: AttributeTarget, visitor: &mut impl Visitor) { + if visitor.visit_secondary_attribute(self, target) { + self.accept_children(target, visitor); + } + } + + pub fn accept_children(&self, target: AttributeTarget, visitor: &mut impl Visitor) { + if let SecondaryAttribute::Custom(custom) = self { + custom.accept(target, visitor); + } + } +} + +impl CustomAtrribute { + pub fn accept(&self, target: AttributeTarget, visitor: &mut impl Visitor) { + visitor.visit_custom_attribute(self, target); } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/comptime.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/comptime.rs index 7da5efd0b5a..0cd0824b6d9 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -15,7 +15,7 @@ use crate::{ }, dc_mod, }, - def_map::ModuleId, + def_map::{LocalModuleId, ModuleId}, resolution::errors::ResolverError, }, hir_def::expr::HirIdent, @@ -30,14 +30,63 @@ use crate::{ use super::{Elaborator, FunctionContext, ResolverMeta}; +#[derive(Debug, Copy, Clone)] +struct AttributeContext { + // The file where generated items should be added + file: FileId, + // The module where generated items should be added + module: LocalModuleId, + // The file where the attribute is located + attribute_file: FileId, + // The module where the attribute is located + attribute_module: LocalModuleId, +} + +impl AttributeContext { + fn new(file: FileId, module: LocalModuleId) -> Self { + Self { file, module, attribute_file: file, attribute_module: module } + } +} + impl<'context> Elaborator<'context> { /// Elaborate an expression from the middle of a comptime scope. /// When this happens we require additional information to know /// what variables should be in scope. - pub fn elaborate_item_from_comptime<'a, T>( + pub fn elaborate_item_from_comptime_in_function<'a, T>( &'a mut self, current_function: Option, f: impl FnOnce(&mut Elaborator<'a>) -> T, + ) -> T { + self.elaborate_item_from_comptime(f, |elaborator| { + if let Some(function) = current_function { + let meta = elaborator.interner.function_meta(&function); + elaborator.current_item = Some(DependencyId::Function(function)); + elaborator.crate_id = meta.source_crate; + elaborator.local_module = meta.source_module; + elaborator.file = meta.source_file; + elaborator.introduce_generics_into_scope(meta.all_generics.clone()); + } + }) + } + + pub fn elaborate_item_from_comptime_in_module<'a, T>( + &'a mut self, + module: ModuleId, + file: FileId, + f: impl FnOnce(&mut Elaborator<'a>) -> T, + ) -> T { + self.elaborate_item_from_comptime(f, |elaborator| { + elaborator.current_item = None; + elaborator.crate_id = module.krate; + elaborator.local_module = module.local_id; + elaborator.file = file; + }) + } + + fn elaborate_item_from_comptime<'a, T>( + &'a mut self, + f: impl FnOnce(&mut Elaborator<'a>) -> T, + setup: impl FnOnce(&mut Elaborator<'a>), ) -> T { // Create a fresh elaborator to ensure no state is changed from // this elaborator @@ -46,21 +95,13 @@ impl<'context> Elaborator<'context> { self.def_maps, self.crate_id, self.debug_comptime_in_file, - self.enable_arithmetic_generics, self.interpreter_call_stack.clone(), ); elaborator.function_context.push(FunctionContext::default()); elaborator.scopes.start_function(); - if let Some(function) = current_function { - let meta = elaborator.interner.function_meta(&function); - elaborator.current_item = Some(DependencyId::Function(function)); - elaborator.crate_id = meta.source_crate; - elaborator.local_module = meta.source_module; - elaborator.file = meta.source_file; - elaborator.introduce_generics_into_scope(meta.all_generics.clone()); - } + setup(&mut elaborator); elaborator.populate_scope_from_comptime_scopes(); @@ -89,15 +130,22 @@ impl<'context> Elaborator<'context> { } } - pub(super) fn run_comptime_attributes_on_item( + fn run_comptime_attributes_on_item( &mut self, attributes: &[SecondaryAttribute], item: Value, span: Span, + attribute_context: AttributeContext, generated_items: &mut CollectedItems, ) { for attribute in attributes { - self.run_comptime_attribute_on_item(attribute, &item, span, generated_items); + self.run_comptime_attribute_on_item( + attribute, + &item, + span, + attribute_context, + generated_items, + ); } } @@ -106,6 +154,7 @@ impl<'context> Elaborator<'context> { attribute: &SecondaryAttribute, item: &Value, span: Span, + attribute_context: AttributeContext, generated_items: &mut CollectedItems, ) { if let SecondaryAttribute::Custom(attribute) = attribute { @@ -114,6 +163,7 @@ impl<'context> Elaborator<'context> { item.clone(), span, attribute.contents_span, + attribute_context, generated_items, ) { self.errors.push(error); @@ -127,8 +177,12 @@ impl<'context> Elaborator<'context> { item: Value, span: Span, attribute_span: Span, + attribute_context: AttributeContext, generated_items: &mut CollectedItems, ) -> Result<(), (CompilationError, FileId)> { + self.file = attribute_context.attribute_file; + self.local_module = attribute_context.attribute_module; + let location = Location::new(attribute_span, self.file); let Some((function, arguments)) = Self::parse_attribute(attribute, location)? else { // Do not issue an error if the attribute is unknown @@ -156,6 +210,9 @@ impl<'context> Elaborator<'context> { return Err((ResolverError::NonFunctionInAnnotation { span }.into(), self.file)); }; + self.file = attribute_context.file; + self.local_module = attribute_context.module; + let mut interpreter = self.setup_interpreter(); let mut arguments = Self::handle_attribute_arguments( &mut interpreter, @@ -318,7 +375,7 @@ impl<'context> Elaborator<'context> { } } - fn add_item( + pub(crate) fn add_item( &mut self, item: TopLevelStatement, generated_items: &mut CollectedItems, @@ -463,18 +520,28 @@ impl<'context> Elaborator<'context> { let attributes = &trait_.trait_def.attributes; let item = Value::TraitDefinition(*trait_id); let span = trait_.trait_def.span; - self.local_module = trait_.module_id; - self.file = trait_.file_id; - self.run_comptime_attributes_on_item(attributes, item, span, &mut generated_items); + let context = AttributeContext::new(trait_.file_id, trait_.module_id); + self.run_comptime_attributes_on_item( + attributes, + item, + span, + context, + &mut generated_items, + ); } for (struct_id, struct_def) in types { let attributes = &struct_def.struct_def.attributes; let item = Value::StructDefinition(*struct_id); let span = struct_def.struct_def.span; - self.local_module = struct_def.module_id; - self.file = struct_def.file_id; - self.run_comptime_attributes_on_item(attributes, item, span, &mut generated_items); + let context = AttributeContext::new(struct_def.file_id, struct_def.module_id); + self.run_comptime_attributes_on_item( + attributes, + item, + span, + context, + &mut generated_items, + ); } self.run_attributes_on_functions(functions, &mut generated_items); @@ -496,10 +563,14 @@ impl<'context> Elaborator<'context> { let attribute = &module_attribute.attribute; let span = Span::default(); - self.local_module = module_attribute.attribute_module_id; - self.file = module_attribute.attribute_file_id; + let context = AttributeContext { + file: module_attribute.file_id, + module: module_attribute.module_id, + attribute_file: module_attribute.attribute_file_id, + attribute_module: module_attribute.attribute_module_id, + }; - self.run_comptime_attribute_on_item(attribute, &item, span, generated_items); + self.run_comptime_attribute_on_item(attribute, &item, span, context, generated_items); } } @@ -509,15 +580,20 @@ impl<'context> Elaborator<'context> { generated_items: &mut CollectedItems, ) { for function_set in function_sets { - self.file = function_set.file_id; self.self_type = function_set.self_type.clone(); for (local_module, function_id, function) in &function_set.functions { - self.local_module = *local_module; + let context = AttributeContext::new(function_set.file_id, *local_module); let attributes = function.secondary_attributes(); let item = Value::FunctionDefinition(*function_id); let span = function.span(); - self.run_comptime_attributes_on_item(attributes, item, span, generated_items); + self.run_comptime_attributes_on_item( + attributes, + item, + span, + context, + generated_items, + ); } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/lints.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/lints.rs index 78df10fa94c..8253921d305 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/lints.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/lints.rs @@ -1,20 +1,19 @@ use crate::{ - ast::FunctionKind, + ast::{FunctionKind, Ident}, graph::CrateId, hir::{ resolution::errors::{PubPosition, ResolverError}, type_check::TypeCheckError, }, - hir_def::expr::HirIdent, + hir_def::{expr::HirIdent, function::FuncMeta}, macros_api::{ - HirExpression, HirLiteral, NodeInterner, NoirFunction, Signedness, UnaryOp, - UnresolvedTypeData, Visibility, + HirExpression, HirLiteral, NodeInterner, NoirFunction, Signedness, UnaryOp, Visibility, }, - node_interner::{DefinitionKind, ExprId, FuncId}, + node_interner::{DefinitionKind, ExprId, FuncId, FunctionModifiers}, Type, }; -use noirc_errors::Span; +use noirc_errors::{Span, Spanned}; pub(super) fn deprecated_function(interner: &NodeInterner, expr: ExprId) -> Option { let HirExpression::Ident(HirIdent { location, id, impl_kind: _ }, _) = @@ -39,16 +38,17 @@ pub(super) fn deprecated_function(interner: &NodeInterner, expr: ExprId) -> Opti /// Inline attributes are only relevant for constrained functions /// as all unconstrained functions are not inlined and so /// associated attributes are disallowed. -pub(super) fn inlining_attributes(func: &NoirFunction) -> Option { - if func.def.is_unconstrained { - let attributes = func.attributes().clone(); - - if attributes.is_no_predicates() { - Some(ResolverError::NoPredicatesAttributeOnUnconstrained { - ident: func.name_ident().clone(), - }) - } else if attributes.is_foldable() { - Some(ResolverError::FoldAttributeOnUnconstrained { ident: func.name_ident().clone() }) +pub(super) fn inlining_attributes( + func: &FuncMeta, + modifiers: &FunctionModifiers, +) -> Option { + if modifiers.is_unconstrained { + if modifiers.attributes.is_no_predicates() { + let ident = func_meta_name_ident(func, modifiers); + Some(ResolverError::NoPredicatesAttributeOnUnconstrained { ident }) + } else if modifiers.attributes.is_foldable() { + let ident = func_meta_name_ident(func, modifiers); + Some(ResolverError::FoldAttributeOnUnconstrained { ident }) } else { None } @@ -59,24 +59,30 @@ pub(super) fn inlining_attributes(func: &NoirFunction) -> Option /// Attempting to define new low level (`#[builtin]` or `#[foreign]`) functions outside of the stdlib is disallowed. pub(super) fn low_level_function_outside_stdlib( - func: &NoirFunction, + func: &FuncMeta, + modifiers: &FunctionModifiers, crate_id: CrateId, ) -> Option { let is_low_level_function = - func.attributes().function.as_ref().map_or(false, |func| func.is_low_level()); + modifiers.attributes.function.as_ref().map_or(false, |func| func.is_low_level()); if !crate_id.is_stdlib() && is_low_level_function { - Some(ResolverError::LowLevelFunctionOutsideOfStdlib { ident: func.name_ident().clone() }) + let ident = func_meta_name_ident(func, modifiers); + Some(ResolverError::LowLevelFunctionOutsideOfStdlib { ident }) } else { None } } /// Oracle definitions (functions with the `#[oracle]` attribute) must be marked as unconstrained. -pub(super) fn oracle_not_marked_unconstrained(func: &NoirFunction) -> Option { +pub(super) fn oracle_not_marked_unconstrained( + func: &FuncMeta, + modifiers: &FunctionModifiers, +) -> Option { let is_oracle_function = - func.attributes().function.as_ref().map_or(false, |func| func.is_oracle()); - if is_oracle_function && !func.def.is_unconstrained { - Some(ResolverError::OracleMarkedAsConstrained { ident: func.name_ident().clone() }) + modifiers.attributes.function.as_ref().map_or(false, |func| func.is_oracle()); + if is_oracle_function && !modifiers.is_unconstrained { + let ident = func_meta_name_ident(func, modifiers); + Some(ResolverError::OracleMarkedAsConstrained { ident }) } else { None } @@ -106,12 +112,13 @@ pub(super) fn oracle_called_from_constrained_function( } /// `pub` is required on return types for entry point functions -pub(super) fn missing_pub(func: &NoirFunction, is_entry_point: bool) -> Option { - if is_entry_point - && func.return_type().typ != UnresolvedTypeData::Unit - && func.def.return_visibility == Visibility::Private +pub(super) fn missing_pub(func: &FuncMeta, modifiers: &FunctionModifiers) -> Option { + if func.is_entry_point + && func.return_type() != &Type::Unit + && func.return_visibility == Visibility::Private { - Some(ResolverError::NecessaryPub { ident: func.name_ident().clone() }) + let ident = func_meta_name_ident(func, modifiers); + Some(ResolverError::NecessaryPub { ident }) } else { None } @@ -119,11 +126,12 @@ pub(super) fn missing_pub(func: &NoirFunction, is_entry_point: bool) -> Option Option { - if !is_entry_point && func.kind == FunctionKind::Recursive { - Some(ResolverError::MisplacedRecursiveAttribute { ident: func.name_ident().clone() }) + if !func.is_entry_point && func.kind == FunctionKind::Recursive { + let ident = func_meta_name_ident(func, modifiers); + Some(ResolverError::MisplacedRecursiveAttribute { ident }) } else { None } @@ -163,14 +171,13 @@ pub(super) fn unconstrained_function_return( /// /// Application of `pub` to other functions is not meaningful and is a mistake. pub(super) fn unnecessary_pub_return( - func: &NoirFunction, + func: &FuncMeta, + modifiers: &FunctionModifiers, is_entry_point: bool, ) -> Option { - if !is_entry_point && func.def.return_visibility == Visibility::Public { - Some(ResolverError::UnnecessaryPub { - ident: func.name_ident().clone(), - position: PubPosition::ReturnType, - }) + if !is_entry_point && func.return_visibility == Visibility::Public { + let ident = func_meta_name_ident(func, modifiers); + Some(ResolverError::UnnecessaryPub { ident, position: PubPosition::ReturnType }) } else { None } @@ -252,3 +259,7 @@ pub(crate) fn overflowing_int( errors } + +fn func_meta_name_ident(func: &FuncMeta, modifiers: &FunctionModifiers) -> Ident { + Ident(Spanned::from(func.name.location.span, modifiers.name.clone())) +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs index 161742029f6..d321d04bef9 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs @@ -26,7 +26,8 @@ use crate::{ SecondaryAttribute, StructId, }, node_interner::{ - DefinitionKind, DependencyId, ExprId, FuncId, GlobalId, ReferenceId, TraitId, TypeAliasId, + DefinitionKind, DependencyId, ExprId, FuncId, FunctionModifiers, GlobalId, ReferenceId, + TraitId, TypeAliasId, }, token::CustomAtrribute, Shared, Type, TypeVariable, @@ -167,9 +168,6 @@ pub struct Elaborator<'context> { /// they are elaborated (e.g. in a function's type or another global's RHS). unresolved_globals: BTreeMap, - /// Temporary flag to enable the experimental arithmetic generics feature - enable_arithmetic_generics: bool, - pub(crate) interpreter_call_stack: im::Vector, } @@ -193,7 +191,6 @@ impl<'context> Elaborator<'context> { def_maps: &'context mut DefMaps, crate_id: CrateId, debug_comptime_in_file: Option, - enable_arithmetic_generics: bool, interpreter_call_stack: im::Vector, ) -> Self { Self { @@ -216,7 +213,6 @@ impl<'context> Elaborator<'context> { current_trait_impl: None, debug_comptime_in_file, unresolved_globals: BTreeMap::new(), - enable_arithmetic_generics, current_trait: None, interpreter_call_stack, } @@ -226,14 +222,12 @@ impl<'context> Elaborator<'context> { context: &'context mut Context, crate_id: CrateId, debug_comptime_in_file: Option, - enable_arithmetic_generics: bool, ) -> Self { Self::new( &mut context.def_interner, &mut context.def_maps, crate_id, debug_comptime_in_file, - enable_arithmetic_generics, im::Vector::new(), ) } @@ -243,16 +237,8 @@ impl<'context> Elaborator<'context> { crate_id: CrateId, items: CollectedItems, debug_comptime_in_file: Option, - enable_arithmetic_generics: bool, ) -> Vec<(CompilationError, FileId)> { - Self::elaborate_and_return_self( - context, - crate_id, - items, - debug_comptime_in_file, - enable_arithmetic_generics, - ) - .errors + Self::elaborate_and_return_self(context, crate_id, items, debug_comptime_in_file).errors } pub fn elaborate_and_return_self( @@ -260,20 +246,14 @@ impl<'context> Elaborator<'context> { crate_id: CrateId, items: CollectedItems, debug_comptime_in_file: Option, - enable_arithmetic_generics: bool, ) -> Self { - let mut this = Self::from_context( - context, - crate_id, - debug_comptime_in_file, - enable_arithmetic_generics, - ); + let mut this = Self::from_context(context, crate_id, debug_comptime_in_file); this.elaborate_items(items); this.check_and_pop_function_context(); this } - fn elaborate_items(&mut self, mut items: CollectedItems) { + pub(crate) fn elaborate_items(&mut self, mut items: CollectedItems) { // We must first resolve and intern the globals before we can resolve any stmts inside each function. // Each function uses its own resolver with a newly created ScopeForest, and must be resolved again to be within a function's scope // @@ -417,6 +397,10 @@ impl<'context> Elaborator<'context> { self.trait_bounds = func_meta.trait_constraints.clone(); self.function_context.push(FunctionContext::default()); + let modifiers = self.interner.function_modifiers(&id).clone(); + + self.run_function_lints(&func_meta, &modifiers); + self.introduce_generics_into_scope(func_meta.all_generics.clone()); // The DefinitionIds for each parameter were already created in define_function_meta @@ -731,20 +715,6 @@ impl<'context> Elaborator<'context> { let is_entry_point = self.is_entry_point_function(func, in_contract); - self.run_lint(|_| lints::inlining_attributes(func).map(Into::into)); - self.run_lint(|_| lints::missing_pub(func, is_entry_point).map(Into::into)); - self.run_lint(|elaborator| { - lints::unnecessary_pub_return(func, elaborator.pub_allowed(func, in_contract)) - .map(Into::into) - }); - self.run_lint(|_| lints::oracle_not_marked_unconstrained(func).map(Into::into)); - self.run_lint(|elaborator| { - lints::low_level_function_outside_stdlib(func, elaborator.crate_id).map(Into::into) - }); - self.run_lint(|_| { - lints::recursive_non_entrypoint_function(func, is_entry_point).map(Into::into) - }); - // Both the #[fold] and #[no_predicates] alter a function's inline type and code generation in similar ways. // In certain cases such as type checking (for which the following flag will be used) both attributes // indicate we should code generate in the same way. Thus, we unify the attributes into one flag here. @@ -858,6 +828,23 @@ impl<'context> Elaborator<'context> { self.current_item = None; } + fn run_function_lints(&mut self, func: &FuncMeta, modifiers: &FunctionModifiers) { + self.run_lint(|_| lints::inlining_attributes(func, modifiers).map(Into::into)); + self.run_lint(|_| lints::missing_pub(func, modifiers).map(Into::into)); + self.run_lint(|_| { + let pub_allowed = func.is_entry_point || modifiers.attributes.is_foldable(); + lints::unnecessary_pub_return(func, modifiers, pub_allowed).map(Into::into) + }); + self.run_lint(|_| lints::oracle_not_marked_unconstrained(func, modifiers).map(Into::into)); + self.run_lint(|elaborator| { + lints::low_level_function_outside_stdlib(func, modifiers, elaborator.crate_id) + .map(Into::into) + }); + self.run_lint(|_| { + lints::recursive_non_entrypoint_function(func, modifiers).map(Into::into) + }); + } + /// Only sized types are valid to be used as main's parameters or the parameters to a contract /// function. If the given type is not sized (e.g. contains a slice or NamedGeneric type), an /// error is issued. diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs index 8dccd5f0344..39ef4e0bb8e 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs @@ -450,7 +450,6 @@ impl<'context> Elaborator<'context> { } UnresolvedTypeExpression::Constant(int, _) => Type::Constant(int), UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, span) => { - let (lhs_span, rhs_span) = (lhs.span(), rhs.span()); let lhs = self.convert_expression_type(*lhs); let rhs = self.convert_expression_type(*rhs); @@ -463,15 +462,7 @@ impl<'context> Elaborator<'context> { Type::Error } } - (lhs, rhs) => { - if !self.enable_arithmetic_generics { - let span = - if !matches!(lhs, Type::Constant(_)) { lhs_span } else { rhs_span }; - self.push_err(ResolverError::InvalidArrayLengthExpr { span }); - } - - Type::InfixExpr(Box::new(lhs), op, Box::new(rhs)).canonicalize() - } + (lhs, rhs) => Type::InfixExpr(Box::new(lhs), op, Box::new(rhs)).canonicalize(), } } UnresolvedTypeExpression::AsTraitPath(path) => self.resolve_as_trait_path(*path), diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs index f6585786eeb..70589973745 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -194,7 +194,6 @@ pub enum InterpreterError { candidates: Vec, location: Location, }, - Unimplemented { item: String, location: Location, @@ -207,6 +206,20 @@ pub enum InterpreterError { index: usize, location: Location, }, + InvalidAttribute { + attribute: String, + location: Location, + }, + GenericNameShouldBeAnIdent { + name: Rc, + location: Location, + }, + DuplicateGeneric { + name: Rc, + struct_name: String, + duplicate_location: Location, + existing_location: Location, + }, // These cases are not errors, they are just used to prevent us from running more code // until the loop can be resumed properly. These cases will never be displayed to users. @@ -275,6 +288,9 @@ impl InterpreterError { | InterpreterError::FunctionAlreadyResolved { location, .. } | InterpreterError::MultipleMatchingImpls { location, .. } | InterpreterError::ExpectedIdentForStructField { location, .. } + | InterpreterError::InvalidAttribute { location, .. } + | InterpreterError::GenericNameShouldBeAnIdent { location, .. } + | InterpreterError::DuplicateGeneric { duplicate_location: location, .. } | InterpreterError::TypeAnnotationsNeededForMethodCall { location } => *location, InterpreterError::FailedToParseMacro { error, file, .. } => { @@ -579,6 +595,37 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic { let secondary = format!("`{value}` is not a valid field name for `set_fields`"); CustomDiagnostic::simple_error(msg, secondary, location.span) } + InterpreterError::InvalidAttribute { attribute, location } => { + let msg = format!("`{attribute}` is not a valid attribute"); + let secondary = "Note that this method expects attribute contents, without the leading `#[` or trailing `]`".to_string(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::GenericNameShouldBeAnIdent { name, location } => { + let msg = + "Generic name needs to be a valid identifer (one word beginning with a letter)" + .to_string(); + let secondary = format!("`{name}` is not a valid identifier"); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::DuplicateGeneric { + name, + struct_name, + duplicate_location, + existing_location, + } => { + let msg = format!("`{struct_name}` already has a generic named `{name}`"); + let secondary = format!("`{name}` added here a second time"); + let mut error = + CustomDiagnostic::simple_error(msg, secondary, duplicate_location.span); + + let existing_msg = format!("`{name}` was previously defined here"); + error.add_secondary_with_file( + existing_msg, + existing_location.span, + existing_location.file, + ); + error + } } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 9f559b7c5e6..5f58c18d66e 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -2,6 +2,7 @@ use std::collections::VecDeque; use std::{collections::hash_map::Entry, rc::Rc}; use acvm::{acir::AcirField, FieldElement}; +use fm::FileId; use im::Vector; use iter_extended::try_vecmap; use noirc_errors::Location; @@ -10,6 +11,7 @@ use rustc_hash::FxHashMap as HashMap; use crate::ast::{BinaryOpKind, FunctionKind, IntegerBitSize, Signedness}; use crate::elaborator::Elaborator; use crate::graph::CrateId; +use crate::hir::def_map::ModuleId; use crate::hir_def::expr::ImplKind; use crate::hir_def::function::FunctionBody; use crate::macros_api::UnaryOp; @@ -170,7 +172,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { Some(body) => Ok(body), None => { if matches!(&meta.function_body, FunctionBody::Unresolved(..)) { - self.elaborate_item(None, |elaborator| { + self.elaborate_in_function(None, |elaborator| { elaborator.elaborate_function(function); }); @@ -183,13 +185,25 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { } } - fn elaborate_item( + fn elaborate_in_function( &mut self, function: Option, f: impl FnOnce(&mut Elaborator) -> T, ) -> T { self.unbind_generics_from_previous_function(); - let result = self.elaborator.elaborate_item_from_comptime(function, f); + let result = self.elaborator.elaborate_item_from_comptime_in_function(function, f); + self.rebind_generics_from_previous_function(); + result + } + + fn elaborate_in_module( + &mut self, + module: ModuleId, + file: FileId, + f: impl FnOnce(&mut Elaborator) -> T, + ) -> T { + self.unbind_generics_from_previous_function(); + let result = self.elaborator.elaborate_item_from_comptime_in_module(module, file, f); self.rebind_generics_from_previous_function(); result } @@ -1244,7 +1258,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { let mut result = self.call_function(function_id, arguments, bindings, location)?; if call.is_macro_call { let expr = result.into_expression(self.elaborator.interner, location)?; - let expr = self.elaborate_item(self.current_function, |elaborator| { + let expr = self.elaborate_in_function(self.current_function, |elaborator| { elaborator.elaborate_expression(expr).0 }); result = self.evaluate(expr)?; 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 65c9c3f018d..c3aeac4aec4 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 @@ -6,13 +6,13 @@ use std::{ use acvm::{AcirField, FieldElement}; use builtin_helpers::{ block_expression_to_value, check_argument_count, check_function_not_yet_resolved, - check_one_argument, check_three_arguments, check_two_arguments, get_expr, get_field, + check_one_argument, check_three_arguments, check_two_arguments, get_bool, get_expr, get_field, get_format_string, get_function_def, get_module, get_quoted, get_slice, get_struct, get_trait_constraint, get_trait_def, get_trait_impl, get_tuple, get_type, get_typed_expr, - get_u32, get_unresolved_type, hir_pattern_to_tokens, mutate_func_meta_type, parse, - replace_func_meta_parameters, replace_func_meta_return_type, + get_u32, get_unresolved_type, has_named_attribute, hir_pattern_to_tokens, + mutate_func_meta_type, parse, replace_func_meta_parameters, replace_func_meta_return_type, }; -use chumsky::{prelude::choice, Parser}; +use chumsky::{chain::Chain, prelude::choice, Parser}; use im::Vector; use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; @@ -25,19 +25,22 @@ use crate::{ FunctionReturnType, IntegerBitSize, LValue, Literal, Statement, StatementKind, UnaryOp, UnresolvedType, UnresolvedTypeData, Visibility, }, - elaborator::Elaborator, - hir::comptime::{ - errors::IResult, - value::{ExprValue, TypedExpr}, - InterpreterError, Value, + hir::def_collector::dc_crate::CollectedItems, + hir::{ + comptime::{ + errors::IResult, + value::{ExprValue, TypedExpr}, + InterpreterError, Value, + }, + def_map::ModuleId, }, hir_def::function::FunctionBody, lexer::Lexer, macros_api::{HirExpression, HirLiteral, Ident, ModuleDefId, NodeInterner, Signedness}, node_interner::{DefinitionKind, TraitImplKind}, parser::{self}, - token::Token, - QuotedType, Shared, Type, + token::{Attribute, SecondaryAttribute, Token}, + Kind, QuotedType, ResolvedGeneric, Shared, Type, TypeVariable, }; use self::builtin_helpers::{get_array, get_str, get_u8}; @@ -97,10 +100,16 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_resolve" => expr_resolve(self, arguments, location), "is_unconstrained" => Ok(Value::Bool(true)), "fmtstr_quoted_contents" => fmtstr_quoted_contents(interner, arguments, location), + "fresh_type_variable" => fresh_type_variable(interner), + "function_def_add_attribute" => function_def_add_attribute(self, arguments, location), "function_def_body" => function_def_body(interner, arguments, location), "function_def_has_named_attribute" => { function_def_has_named_attribute(interner, arguments, location) } + "function_def_is_unconstrained" => { + function_def_is_unconstrained(interner, arguments, location) + } + "function_def_module" => function_def_module(interner, arguments, location), "function_def_name" => function_def_name(interner, arguments, location), "function_def_parameters" => function_def_parameters(interner, arguments, location), "function_def_return_type" => function_def_return_type(interner, arguments, location), @@ -109,6 +118,13 @@ impl<'local, 'context> Interpreter<'local, 'context> { "function_def_set_return_type" => { function_def_set_return_type(self, arguments, location) } + "function_def_set_return_public" => { + function_def_set_return_public(self, arguments, location) + } + "function_def_set_unconstrained" => { + function_def_set_unconstrained(self, arguments, location) + } + "module_add_item" => module_add_item(self, arguments, location), "module_functions" => module_functions(self, arguments, location), "module_has_named_attribute" => module_has_named_attribute(self, arguments, location), "module_is_contract" => module_is_contract(self, arguments, location), @@ -123,6 +139,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "quoted_as_trait_constraint" => quoted_as_trait_constraint(self, arguments, location), "quoted_as_type" => quoted_as_type(self, arguments, location), "quoted_eq" => quoted_eq(arguments, location), + "quoted_tokens" => quoted_tokens(arguments, location), "slice_insert" => slice_insert(interner, arguments, location), "slice_pop_back" => slice_pop_back(interner, arguments, location, call_stack), "slice_pop_front" => slice_pop_front(interner, arguments, location, call_stack), @@ -130,9 +147,16 @@ impl<'local, 'context> Interpreter<'local, 'context> { "slice_push_front" => slice_push_front(interner, arguments, location), "slice_remove" => slice_remove(interner, arguments, location, call_stack), "str_as_bytes" => str_as_bytes(interner, arguments, location), + "struct_def_add_attribute" => struct_def_add_attribute(interner, arguments, location), + "struct_def_add_generic" => struct_def_add_generic(interner, arguments, location), "struct_def_as_type" => struct_def_as_type(interner, arguments, location), "struct_def_fields" => struct_def_fields(interner, arguments, location), "struct_def_generics" => struct_def_generics(interner, arguments, location), + "struct_def_has_named_attribute" => { + struct_def_has_named_attribute(interner, arguments, location) + } + "struct_def_module" => struct_def_module(self, arguments, location), + "struct_def_name" => struct_def_name(interner, arguments, location), "struct_def_set_fields" => struct_def_set_fields(interner, arguments, location), "to_le_radix" => to_le_radix(arguments, return_type, location), "trait_constraint_eq" => trait_constraint_eq(interner, arguments, location), @@ -263,6 +287,105 @@ fn str_as_bytes( Ok(Value::Array(bytes, byte_array_type)) } +// fn add_attribute(self, attribute: str) +fn struct_def_add_attribute( + interner: &mut NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (self_argument, attribute) = check_two_arguments(arguments, location)?; + let attribute_location = attribute.1; + let attribute = get_str(interner, attribute)?; + + let mut tokens = Lexer::lex(&format!("#[{}]", attribute)).0 .0; + if let Some(Token::EOF) = tokens.last().map(|token| token.token()) { + tokens.pop(); + } + if tokens.len() != 1 { + return Err(InterpreterError::InvalidAttribute { + attribute: attribute.to_string(), + location: attribute_location, + }); + } + + let token = tokens.into_iter().next().unwrap().into_token(); + let Token::Attribute(attribute) = token else { + return Err(InterpreterError::InvalidAttribute { + attribute: attribute.to_string(), + location: attribute_location, + }); + }; + + let Attribute::Secondary(attribute) = attribute else { + return Err(InterpreterError::InvalidAttribute { + attribute: attribute.to_string(), + location: attribute_location, + }); + }; + + let struct_id = get_struct(self_argument)?; + interner.update_struct_attributes(struct_id, |attributes| { + attributes.push(attribute.clone()); + }); + + Ok(Value::Unit) +} + +// fn add_generic(self, generic_name: str) +fn struct_def_add_generic( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (self_argument, generic) = check_two_arguments(arguments, location)?; + let generic_location = generic.1; + let generic = get_str(interner, generic)?; + + let mut tokens = Lexer::lex(&generic).0 .0; + if let Some(Token::EOF) = tokens.last().map(|token| token.token()) { + tokens.pop(); + } + + if tokens.len() != 1 { + return Err(InterpreterError::GenericNameShouldBeAnIdent { + name: generic, + location: generic_location, + }); + } + + let Token::Ident(generic_name) = tokens.pop().unwrap().into_token() else { + return Err(InterpreterError::GenericNameShouldBeAnIdent { + name: generic, + location: generic_location, + }); + }; + + let struct_id = get_struct(self_argument)?; + let the_struct = interner.get_struct(struct_id); + let mut the_struct = the_struct.borrow_mut(); + let name = Rc::new(generic_name); + + for generic in &the_struct.generics { + if generic.name == name { + return Err(InterpreterError::DuplicateGeneric { + name, + struct_name: the_struct.name.to_string(), + existing_location: Location::new(generic.span, the_struct.location.file), + duplicate_location: generic_location, + }); + } + } + + let type_var = TypeVariable::unbound(interner.next_type_variable_id()); + let span = generic_location.span; + let kind = Kind::Normal; + let typ = Type::NamedGeneric(type_var.clone(), name.clone(), kind.clone()); + let new_generic = ResolvedGeneric { name, type_var, span, kind }; + the_struct.generics.push(new_generic); + + Ok(Value::Type(typ)) +} + /// fn as_type(self) -> Type fn struct_def_as_type( interner: &NodeInterner, @@ -300,6 +423,25 @@ fn struct_def_generics( Ok(Value::Slice(generics.collect(), typ)) } +// fn has_named_attribute(self, name: Quoted) -> bool +fn struct_def_has_named_attribute( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (self_argument, name) = check_two_arguments(arguments, location)?; + let struct_id = get_struct(self_argument)?; + + let name = get_quoted(name)?; + let name = name.iter().map(|token| token.to_string()).collect::>().join(""); + + let attributes = interner.struct_attributes(&struct_id); + let attributes = attributes.iter().filter_map(|attribute| attribute.as_custom()); + let attributes = attributes.map(|attribute| &attribute.contents); + + Ok(Value::Bool(has_named_attribute(&name, attributes, location))) +} + /// fn fields(self) -> [(Quoted, Type)] /// Returns (name, type) pairs of each field of this StructDefinition fn struct_def_fields( @@ -327,6 +469,39 @@ fn struct_def_fields( Ok(Value::Slice(fields, typ)) } +// fn module(self) -> Module +fn struct_def_module( + interpreter: &Interpreter, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let struct_id = get_struct(self_argument)?; + let struct_module_id = struct_id.module_id(); + + // A struct's module is its own module. To get the module where its defined we need + // to look for its parent. + let module_data = interpreter.elaborator.get_module(struct_module_id); + let parent_local_id = module_data.parent.expect("Expected struct module parent to exist"); + let parent = ModuleId { krate: struct_module_id.krate, local_id: parent_local_id }; + + Ok(Value::ModuleDefinition(parent)) +} + +// fn name(self) -> Quoted +fn struct_def_name( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let struct_id = get_struct(self_argument)?; + let the_struct = interner.get_struct(struct_id); + + let name = Token::Ident(the_struct.borrow().name.to_string()); + Ok(Value::Quoted(Rc::new(vec![name]))) +} + /// fn set_fields(self, new_fields: [(Quoted, Type)]) {} /// Returns (name, type) pairs of each field of this StructDefinition fn struct_def_set_fields( @@ -496,9 +671,10 @@ fn quoted_as_module( let path = parse(argument, parser::path_no_turbofish(), "a path").ok(); let option_value = path.and_then(|path| { - let module = interpreter.elaborate_item(interpreter.current_function, |elaborator| { - elaborator.resolve_module_by_path(path) - }); + let module = interpreter + .elaborate_in_function(interpreter.current_function, |elaborator| { + elaborator.resolve_module_by_path(path) + }); module.map(Value::ModuleDefinition) }); @@ -514,7 +690,7 @@ fn quoted_as_trait_constraint( let argument = check_one_argument(arguments, location)?; let trait_bound = parse(argument, parser::trait_bound(), "a trait constraint")?; let bound = interpreter - .elaborate_item(interpreter.current_function, |elaborator| { + .elaborate_in_function(interpreter.current_function, |elaborator| { elaborator.resolve_trait_bound(&trait_bound, Type::Unit) }) .ok_or(InterpreterError::FailedToResolveTraitBound { trait_bound, location })?; @@ -530,11 +706,22 @@ fn quoted_as_type( ) -> IResult { let argument = check_one_argument(arguments, location)?; let typ = parse(argument, parser::parse_type(), "a type")?; - let typ = - interpreter.elaborate_item(interpreter.current_function, |elab| elab.resolve_type(typ)); + let typ = interpreter + .elaborate_in_function(interpreter.current_function, |elab| elab.resolve_type(typ)); Ok(Value::Type(typ)) } +// fn tokens(quoted: Quoted) -> [Quoted] +fn quoted_tokens(arguments: Vec<(Value, Location)>, location: Location) -> IResult { + let argument = check_one_argument(arguments, location)?; + let value = get_quoted(argument)?; + + Ok(Value::Slice( + value.iter().map(|token| Value::Quoted(Rc::new(vec![token.clone()]))).collect(), + Type::Slice(Box::new(Type::Quoted(QuotedType::Quoted))), + )) +} + fn to_le_radix( arguments: Vec<(Value, Location)>, return_type: Type, @@ -598,11 +785,10 @@ fn type_as_constant( location: Location, ) -> IResult { type_as(arguments, return_type, location, |typ| { - if let Type::Constant(n) = typ { - Some(Value::U32(n)) - } else { - None - } + // Prefer to use `evaluate_to_u32` over matching on `Type::Constant` + // since arithmetic generics may be `Type::InfixExpr`s which evaluate to + // constants but are not actually the `Type::Constant` variant. + typ.evaluate_to_u32().map(Value::U32) }) } @@ -704,7 +890,7 @@ where F: FnOnce(Type) -> Option, { let value = check_one_argument(arguments, location)?; - let typ = get_type(value)?; + let typ = get_type(value)?.follow_bindings(); let option_value = f(typ); @@ -733,13 +919,13 @@ fn type_get_trait_impl( let typ = get_type(typ)?; let (trait_id, generics) = get_trait_constraint(constraint)?; - let option_value = match interner.try_lookup_trait_implementation( + let option_value = match interner.lookup_trait_implementation( &typ, trait_id, &generics.ordered, &generics.named, ) { - Ok((TraitImplKind::Normal(trait_impl_id), _)) => Some(Value::TraitImpl(trait_impl_id)), + Ok(TraitImplKind::Normal(trait_impl_id)) => Some(Value::TraitImpl(trait_impl_id)), _ => None, }; @@ -758,7 +944,7 @@ fn type_implements( let (trait_id, generics) = get_trait_constraint(constraint)?; let implements = interner - .try_lookup_trait_implementation(&typ, trait_id, &generics.ordered, &generics.named) + .lookup_trait_implementation(&typ, trait_id, &generics.ordered, &generics.named) .is_ok(); Ok(Value::Bool(implements)) } @@ -1591,23 +1777,25 @@ fn expr_resolve( interpreter.current_function }; - let value = interpreter.elaborate_item(function_to_resolve_in, |elaborator| match expr_value { - ExprValue::Expression(expression_kind) => { - let expr = Expression { kind: expression_kind, span: self_argument_location.span }; - let (expr_id, _) = elaborator.elaborate_expression(expr); - Value::TypedExpr(TypedExpr::ExprId(expr_id)) - } - ExprValue::Statement(statement_kind) => { - let statement = Statement { kind: statement_kind, span: self_argument_location.span }; - let (stmt_id, _) = elaborator.elaborate_statement(statement); - Value::TypedExpr(TypedExpr::StmtId(stmt_id)) - } - ExprValue::LValue(lvalue) => { - let expr = lvalue.as_expression(); - let (expr_id, _) = elaborator.elaborate_expression(expr); - Value::TypedExpr(TypedExpr::ExprId(expr_id)) - } - }); + let value = + interpreter.elaborate_in_function(function_to_resolve_in, |elaborator| match expr_value { + ExprValue::Expression(expression_kind) => { + let expr = Expression { kind: expression_kind, span: self_argument_location.span }; + let (expr_id, _) = elaborator.elaborate_expression(expr); + Value::TypedExpr(TypedExpr::ExprId(expr_id)) + } + ExprValue::Statement(statement_kind) => { + let statement = + Statement { kind: statement_kind, span: self_argument_location.span }; + let (stmt_id, _) = elaborator.elaborate_statement(statement); + Value::TypedExpr(TypedExpr::StmtId(stmt_id)) + } + ExprValue::LValue(lvalue) => { + let expr = lvalue.as_expression(); + let (expr_id, _) = elaborator.elaborate_expression(expr); + Value::TypedExpr(TypedExpr::ExprId(expr_id)) + } + }); Ok(value) } @@ -1654,6 +1842,62 @@ fn fmtstr_quoted_contents( Ok(Value::Quoted(Rc::new(tokens))) } +// fn fresh_type_variable() -> Type +fn fresh_type_variable(interner: &NodeInterner) -> IResult { + Ok(Value::Type(interner.next_type_variable())) +} + +// fn add_attribute(self, attribute: str) +fn function_def_add_attribute( + interpreter: &mut Interpreter, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (self_argument, attribute) = check_two_arguments(arguments, location)?; + let attribute_location = attribute.1; + let attribute = get_str(interpreter.elaborator.interner, attribute)?; + + let mut tokens = Lexer::lex(&format!("#[{}]", attribute)).0 .0; + if let Some(Token::EOF) = tokens.last().map(|token| token.token()) { + tokens.pop(); + } + if tokens.len() != 1 { + return Err(InterpreterError::InvalidAttribute { + attribute: attribute.to_string(), + location: attribute_location, + }); + } + + let token = tokens.into_iter().next().unwrap().into_token(); + let Token::Attribute(attribute) = token else { + return Err(InterpreterError::InvalidAttribute { + attribute: attribute.to_string(), + location: attribute_location, + }); + }; + + let func_id = get_function_def(self_argument)?; + check_function_not_yet_resolved(interpreter, func_id, location)?; + + let function_modifiers = interpreter.elaborator.interner.function_modifiers_mut(&func_id); + + match &attribute { + Attribute::Function(attribute) => { + function_modifiers.attributes.function = Some(attribute.clone()); + } + Attribute::Secondary(attribute) => { + function_modifiers.attributes.secondary.push(attribute.clone()); + } + } + + if let Attribute::Secondary(SecondaryAttribute::Custom(attribute)) = attribute { + let func_meta = interpreter.elaborator.interner.function_meta_mut(&func_id); + func_meta.custom_attributes.push(attribute); + } + + Ok(Value::Unit) +} + // fn body(self) -> Expr fn function_def_body( interner: &NodeInterner, @@ -1678,31 +1922,39 @@ fn function_def_has_named_attribute( ) -> IResult { let (self_argument, name) = check_two_arguments(arguments, location)?; let func_id = get_function_def(self_argument)?; - let name = get_quoted(name)?; let func_meta = interner.function_meta(&func_id); - let attributes = &func_meta.custom_attributes; - if attributes.is_empty() { - return Ok(Value::Bool(false)); - }; + let name = get_quoted(name)?; let name = name.iter().map(|token| token.to_string()).collect::>().join(""); - for attribute in attributes { - let parse_result = Elaborator::parse_attribute(&attribute.contents, location); - let Ok(Some((function, _arguments))) = parse_result else { - continue; - }; + let attributes = &func_meta.custom_attributes; + let attributes = attributes.iter().map(|attribute| &attribute.contents); - let ExpressionKind::Variable(path) = function.kind else { - continue; - }; + Ok(Value::Bool(has_named_attribute(&name, attributes, location))) +} - if path.last_name() == name { - return Ok(Value::Bool(true)); - } - } +// fn is_unconstrained(self) -> bool +fn function_def_is_unconstrained( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let func_id = get_function_def(self_argument)?; + let is_unconstrained = interner.function_modifiers(&func_id).is_unconstrained; + Ok(Value::Bool(is_unconstrained)) +} - Ok(Value::Bool(false)) +// fn module(self) -> Module +fn function_def_module( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let func_id = get_function_def(self_argument)?; + let module = interner.function_module(func_id); + Ok(Value::ModuleDefinition(module)) } // fn name(self) -> Quoted @@ -1823,7 +2075,7 @@ fn function_def_set_parameters( "a pattern", )?; - let hir_pattern = interpreter.elaborate_item(Some(func_id), |elaborator| { + let hir_pattern = interpreter.elaborate_in_function(Some(func_id), |elaborator| { elaborator.elaborate_pattern_and_store_ids( parameter_pattern, parameter_type.clone(), @@ -1871,6 +2123,72 @@ fn function_def_set_return_type( Ok(Value::Unit) } +// fn set_return_public(self, public: bool) +fn function_def_set_return_public( + interpreter: &mut Interpreter, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (self_argument, public) = check_two_arguments(arguments, location)?; + + let func_id = get_function_def(self_argument)?; + check_function_not_yet_resolved(interpreter, func_id, location)?; + + let public = get_bool(public)?; + + let func_meta = interpreter.elaborator.interner.function_meta_mut(&func_id); + func_meta.return_visibility = if public { Visibility::Public } else { Visibility::Private }; + + Ok(Value::Unit) +} + +// fn set_unconstrained(self, value: bool) +fn function_def_set_unconstrained( + interpreter: &mut Interpreter, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (self_argument, unconstrained) = check_two_arguments(arguments, location)?; + + let func_id = get_function_def(self_argument)?; + check_function_not_yet_resolved(interpreter, func_id, location)?; + + let unconstrained = get_bool(unconstrained)?; + + let modifiers = interpreter.elaborator.interner.function_modifiers_mut(&func_id); + modifiers.is_unconstrained = unconstrained; + + Ok(Value::Unit) +} + +// fn add_item(self, item: Quoted) +fn module_add_item( + interpreter: &mut Interpreter, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (self_argument, item) = check_two_arguments(arguments, location)?; + let module_id = get_module(self_argument)?; + let module_data = interpreter.elaborator.get_module(module_id); + + let parser = parser::top_level_items(); + let top_level_statements = parse(item, parser, "a top-level item")?; + + interpreter.elaborate_in_module(module_id, module_data.location.file, |elaborator| { + let mut generated_items = CollectedItems::default(); + + for top_level_statement in top_level_statements { + elaborator.add_item(top_level_statement, &mut generated_items, location); + } + + if !generated_items.is_empty() { + elaborator.elaborate_items(generated_items); + } + }); + + Ok(Value::Unit) +} + // fn functions(self) -> [FunctionDefinition] fn module_functions( interpreter: &Interpreter, @@ -1904,27 +2222,13 @@ fn module_has_named_attribute( let (self_argument, name) = check_two_arguments(arguments, location)?; let module_id = get_module(self_argument)?; let module_data = interpreter.elaborator.get_module(module_id); - let name = get_quoted(name)?; + let name = get_quoted(name)?; let name = name.iter().map(|token| token.to_string()).collect::>().join(""); let attributes = module_data.outer_attributes.iter().chain(&module_data.inner_attributes); - for attribute in attributes { - let parse_result = Elaborator::parse_attribute(attribute, location); - let Ok(Some((function, _arguments))) = parse_result else { - continue; - }; - - let ExpressionKind::Variable(path) = function.kind else { - continue; - }; - - if path.last_name() == name { - return Ok(Value::Bool(true)); - } - } - Ok(Value::Bool(false)) + Ok(Value::Bool(has_named_attribute(&name, attributes, location))) } // fn is_contract(self) -> bool diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs index ff3da6d253f..f90d50807b8 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs @@ -8,6 +8,7 @@ use crate::{ BlockExpression, ExpressionKind, IntegerBitSize, LValue, Signedness, StatementKind, UnresolvedTypeData, }, + elaborator::Elaborator, hir::{ comptime::{ errors::IResult, @@ -90,6 +91,13 @@ pub(crate) fn get_array( } } +pub(crate) fn get_bool((value, location): (Value, Location)) -> IResult { + match value { + Value::Bool(value) => Ok(value), + value => type_mismatch(value, Type::Bool, location), + } +} + pub(crate) fn get_slice( interner: &NodeInterner, (value, location): (Value, Location), @@ -437,3 +445,26 @@ pub(super) fn block_expression_to_value(block_expr: BlockExpression) -> Value { Value::Slice(statements, typ) } + +pub(super) fn has_named_attribute<'a>( + name: &'a str, + attributes: impl Iterator, + location: Location, +) -> bool { + for attribute in attributes { + let parse_result = Elaborator::parse_attribute(attribute, location); + let Ok(Some((function, _arguments))) = parse_result else { + continue; + }; + + let ExpressionKind::Variable(path) = function.kind else { + continue; + }; + + if path.last_name() == name { + return true; + } + } + + false +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/tests.rs index 64b489422a0..a47dbeace50 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/tests.rs @@ -51,7 +51,7 @@ fn interpret_helper(src: &str) -> Result { let main = context.get_main_function(&krate).expect("Expected 'main' function"); let mut elaborator = - Elaborator::elaborate_and_return_self(&mut context, krate, collector.items, None, false); + Elaborator::elaborate_and_return_self(&mut context, krate, collector.items, None); assert_eq!(elaborator.errors.len(), 0); let mut interpreter = elaborator.setup_interpreter(); 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 7d6e4475c7b..04c557552bd 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 @@ -653,9 +653,15 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { Value::FunctionDefinition(function_id) => { write!(f, "{}", self.interner.function_name(function_id)) } - Value::ModuleDefinition(_) => write!(f, "(module)"), + Value::ModuleDefinition(module_id) => { + if let Some(attributes) = self.interner.try_module_attributes(module_id) { + write!(f, "{}", &attributes.name) + } else { + write!(f, "(crate root)") + } + } Value::Zeroed(typ) => write!(f, "(zeroed {typ})"), - Value::Type(typ) => write!(f, "{}", typ), + Value::Type(typ) => write!(f, "{:?}", typ), Value::Expr(ExprValue::Expression(expr)) => { write!(f, "{}", remove_interned_in_expression_kind(self.interner, expr.clone())) } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 3cfa0989d7d..7ee1840690a 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -271,7 +271,6 @@ impl DefCollector { ast: SortedModule, root_file_id: FileId, debug_comptime_in_file: Option<&str>, - enable_arithmetic_generics: bool, error_on_unused_items: bool, macro_processors: &[&dyn MacroProcessor], ) -> Vec<(CompilationError, FileId)> { @@ -291,7 +290,6 @@ impl DefCollector { dep.crate_id, context, debug_comptime_in_file, - enable_arithmetic_generics, error_on_usage_tracker, macro_processors, )); @@ -471,13 +469,8 @@ impl DefCollector { }) }); - let mut more_errors = Elaborator::elaborate( - context, - crate_id, - def_collector.items, - debug_comptime_in_file, - enable_arithmetic_generics, - ); + let mut more_errors = + Elaborator::elaborate(context, crate_id, def_collector.items, debug_comptime_in_file); errors.append(&mut more_errors); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs index a1c4d04cb30..75b860bf2c6 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -76,7 +76,6 @@ impl CrateDefMap { crate_id: CrateId, context: &mut Context, debug_comptime_in_file: Option<&str>, - enable_arithmetic_generics: bool, error_on_unused_imports: bool, macro_processors: &[&dyn MacroProcessor], ) -> Vec<(CompilationError, FileId)> { @@ -133,7 +132,6 @@ impl CrateDefMap { ast, root_file_id, debug_comptime_in_file, - enable_arithmetic_generics, error_on_unused_imports, macro_processors, )); 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 113a4fb3888..d47e6522756 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 @@ -1099,13 +1099,19 @@ impl Type { | Type::Unit | Type::Constant(_) | Type::Slice(_) - | Type::TypeVariable(_, _) - | Type::NamedGeneric(_, _, _) | Type::Function(_, _, _, _) | Type::FmtString(_, _) | Type::InfixExpr(..) | Type::Error => true, + Type::TypeVariable(type_var, _) | Type::NamedGeneric(type_var, _, _) => { + if let TypeBinding::Bound(typ) = &*type_var.borrow() { + typ.is_valid_for_unconstrained_boundary() + } else { + true + } + } + // Quoted objects only exist at compile-time where the only execution // environment is the interpreter. In this environment, they are valid. Type::Quoted(_) => true, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/mod.rs index 596d15176bc..66be0fdced5 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/mod.rs @@ -26,7 +26,8 @@ use noirc_errors::Span; pub use parser::path::path_no_turbofish; pub use parser::traits::trait_bound; pub use parser::{ - block, expression, fresh_statement, lvalue, parse_program, parse_type, pattern, top_level_items, + block, expression, fresh_statement, lvalue, module, parse_program, parse_type, pattern, + top_level_items, top_level_statement, visibility, }; #[derive(Debug, Clone)] 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 2bc7a88c6c5..48d25e7a1d8 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs @@ -28,7 +28,8 @@ use self::primitives::{keyword, macro_quote_marker, mutable_reference, variable} use self::types::{generic_type_args, maybe_comp_time}; use attributes::{attributes, inner_attribute, validate_secondary_attributes}; pub use types::parse_type; -use visibility::visibility_modifier; +use visibility::item_visibility; +pub use visibility::visibility; use super::{ foldl_with_span, labels::ParsingRuleLabel, parameter_name_recovery, parameter_recovery, @@ -174,7 +175,7 @@ fn program() -> impl NoirParser { /// module: top_level_statement module /// | %empty -fn module() -> impl NoirParser { +pub fn module() -> impl NoirParser { recursive(|module_parser| { empty() .to(ParsedModule::default()) @@ -201,7 +202,7 @@ pub fn top_level_items() -> impl NoirParser> { /// | module_declaration /// | use_statement /// | global_declaration -fn top_level_statement<'a>( +pub fn top_level_statement<'a>( module_parser: impl NoirParser + 'a, ) -> impl NoirParser + 'a { choice(( @@ -459,7 +460,7 @@ fn module_declaration() -> impl NoirParser { } fn use_statement() -> impl NoirParser { - visibility_modifier() + item_visibility() .then_ignore(keyword(Keyword::Use)) .then(use_tree()) .map(|(visibility, use_tree)| TopLevelStatement::Import(use_tree, visibility)) @@ -737,15 +738,6 @@ fn call_data() -> impl NoirParser { }) } -fn optional_visibility() -> impl NoirParser { - keyword(Keyword::Pub) - .map(|_| Visibility::Public) - .or(call_data()) - .or(keyword(Keyword::ReturnData).map(|_| Visibility::ReturnData)) - .or_not() - .map(|opt| opt.unwrap_or(Visibility::Private)) -} - pub fn expression() -> impl ExprParser { recursive(|expr| { expression_with_precedence( diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/function.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/function.rs index 9328c882e54..05138bfffd9 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/function.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/function.rs @@ -1,10 +1,10 @@ use super::{ attributes::{attributes, validate_attributes}, - block, fresh_statement, ident, keyword, maybe_comp_time, nothing, optional_visibility, - parameter_name_recovery, parameter_recovery, parenthesized, parse_type, pattern, + block, fresh_statement, ident, keyword, maybe_comp_time, nothing, parameter_name_recovery, + parameter_recovery, parenthesized, parse_type, pattern, primitives::token_kind, self_parameter, - visibility::visibility_modifier, + visibility::{item_visibility, visibility}, where_clause, NoirParser, }; use crate::token::{Keyword, Token, TokenKind}; @@ -79,13 +79,9 @@ pub(super) fn function_definition(allow_self: bool) -> impl NoirParser impl NoirParser<(bool, ItemVisibility, bool)> { - keyword(Keyword::Unconstrained) - .or_not() - .then(visibility_modifier()) - .then(maybe_comp_time()) - .map(|((unconstrained, visibility), comptime)| { - (unconstrained.is_some(), visibility, comptime) - }) + keyword(Keyword::Unconstrained).or_not().then(item_visibility()).then(maybe_comp_time()).map( + |((unconstrained, visibility), comptime)| (unconstrained.is_some(), visibility, comptime), + ) } pub(super) fn numeric_generic() -> impl NoirParser { @@ -142,14 +138,12 @@ pub(super) fn generics() -> impl NoirParser { pub(super) fn function_return_type() -> impl NoirParser<(Visibility, FunctionReturnType)> { #[allow(deprecated)] - just(Token::Arrow) - .ignore_then(optional_visibility()) - .then(spanned(parse_type())) - .or_not() - .map_with_span(|ret, span| match ret { + just(Token::Arrow).ignore_then(visibility()).then(spanned(parse_type())).or_not().map_with_span( + |ret, span| match ret { Some((visibility, (ty, _))) => (visibility, FunctionReturnType::Ty(ty)), None => (Visibility::Private, FunctionReturnType::Default(span)), - }) + }, + ) } fn function_parameters<'a>(allow_self: bool) -> impl NoirParser> + 'a { @@ -158,7 +152,7 @@ fn function_parameters<'a>(allow_self: bool) -> impl NoirParser> + 'a let full_parameter = pattern() .recover_via(parameter_name_recovery()) .then_ignore(just(Token::Colon)) - .then(optional_visibility()) + .then(visibility()) .then(typ) .map_with_span(|((pattern, visibility), typ), span| Param { visibility, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/visibility.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/visibility.rs index d9c1abf2123..ea46becc932 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/visibility.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/visibility.rs @@ -4,15 +4,15 @@ use chumsky::{ }; use crate::{ - ast::ItemVisibility, + ast::{ItemVisibility, Visibility}, parser::NoirParser, token::{Keyword, Token}, }; -use super::primitives::keyword; +use super::{call_data, primitives::keyword}; /// visibility_modifier: 'pub(crate)'? 'pub'? '' -pub(crate) fn visibility_modifier() -> impl NoirParser { +pub(crate) fn item_visibility() -> impl NoirParser { let is_pub_crate = (keyword(Keyword::Pub) .then_ignore(just(Token::LeftParen)) .then_ignore(keyword(Keyword::Crate)) @@ -25,3 +25,12 @@ pub(crate) fn visibility_modifier() -> impl NoirParser { choice((is_pub_crate, is_pub, is_private)) } + +pub fn visibility() -> impl NoirParser { + keyword(Keyword::Pub) + .map(|_| Visibility::Public) + .or(call_data()) + .or(keyword(Keyword::ReturnData).map(|_| Visibility::ReturnData)) + .or_not() + .map(|opt| opt.unwrap_or(Visibility::Private)) +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs index 04c4e414858..3e01c370154 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs @@ -96,7 +96,6 @@ pub(crate) fn get_program(src: &str) -> (ParsedModule, Context, Vec<(Compilation }; let debug_comptime_in_file = None; - let enable_arithmetic_generics = false; let error_on_unused_imports = true; let macro_processors = &[]; @@ -107,7 +106,6 @@ pub(crate) fn get_program(src: &str) -> (ParsedModule, Context, Vec<(Compilation program.clone().into_sorted(), root_file_id, debug_comptime_in_file, - enable_arithmetic_generics, error_on_unused_imports, macro_processors, )); @@ -3366,7 +3364,7 @@ fn warns_on_re_export_of_item_with_less_visibility() { } #[test] -fn unoquted_integer_as_integer_token() { +fn unquoted_integer_as_integer_token() { let src = r#" trait Serialize { fn serialize() {} @@ -3377,7 +3375,7 @@ fn unoquted_integer_as_integer_token() { fn attr(_f: FunctionDefinition) -> Quoted { let serialized_len = 1; - // We are testing that when we unoqute $serialized_len, it's unquoted + // We are testing that when we unquote $serialized_len, it's unquoted // as the token `1` and not as something else that later won't be parsed correctly // in the context of a generic argument. quote { @@ -3424,3 +3422,32 @@ fn errors_on_unused_function() { assert_eq!(ident.to_string(), "foo"); assert_eq!(*item_type, "function"); } + +#[test] +fn constrained_reference_to_unconstrained() { + let src = r#" + fn main(mut x: u32, y: pub u32) { + let x_ref = &mut x; + if x == 5 { + unsafe { + mut_ref_input(x_ref, y); + } + } + + assert(x == 10); + } + + unconstrained fn mut_ref_input(x: &mut u32, y: u32) { + *x = y; + } + "#; + + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + let CompilationError::TypeError(TypeCheckError::ConstrainedReferenceToUnconstrained { .. }) = + &errors[0].0 + else { + panic!("Expected an error about passing a constrained reference to unconstrained"); + }; +} diff --git a/noir/noir-repo/docs/docs/noir/concepts/generics.md b/noir/noir-repo/docs/docs/noir/concepts/generics.md index 3e416eee093..f05540f9f55 100644 --- a/noir/noir-repo/docs/docs/noir/concepts/generics.md +++ b/noir/noir-repo/docs/docs/noir/concepts/generics.md @@ -45,17 +45,20 @@ fn main() { The `print` function will print `Hello!` an arbitrary number of times, twice in this case. +## Numeric Generics + If we want to be generic over array lengths (which are type-level integers), we can use numeric -generics. Using these looks just like using regular generics, but these generics can resolve to -integers at compile-time, rather than resolving to types. Here's an example of a struct that is -generic over the size of the array it contains internally: +generics. Using these looks similar to using regular generics, but introducing them into scope +requires declaring them with `let MyGenericName: IntegerType`. This can be done anywhere a normal +generic is declared. Instead of types, these generics resolve to integers at compile-time. +Here's an example of a struct that is generic over the size of the array it contains internally: ```rust -struct BigInt { +struct BigInt { limbs: [u32; N], } -impl BigInt { +impl BigInt { // `N` is in scope of all methods in the impl fn first(first: BigInt, second: BigInt) -> Self { assert(first.limbs != second.limbs); @@ -77,7 +80,7 @@ This is what [traits](../concepts/traits.md) are for in Noir. Here's an example any type `T` that implements the `Eq` trait for equality: ```rust -fn first_element_is_equal(array1: [T; N], array2: [T; N]) -> bool +fn first_element_is_equal(array1: [T; N], array2: [T; N]) -> bool where T: Eq { if (array1.len() == 0) | (array2.len() == 0) { @@ -161,3 +164,47 @@ fn example() { assert(10 as u32 == foo.generic_method::()); } ``` + +## Arithmetic Generics + +In addition to numeric generics, Noir also allows a limited form of arithmetic on generics. +When you have a numeric generic such as `N`, you can use the following operators on it in a +type position: `+`, `-`, `*`, `/`, and `%`. + +Note that type checking arithmetic generics is a best effort guess from the compiler and there +are many cases of types that are equal that the compiler may not see as such. For example, +we know that `T * (N + M)` should be equal to `T*N + T*M` but the compiler does not currently +apply the distributive law and thus sees these as different types. + +Even with this limitation though, the compiler can handle common cases decently well: + +```rust +trait Serialize { + fn serialize(self) -> [Field; N]; +} + +impl Serialize<1> for Field { + fn serialize(self) -> [Field; 1] { + [self] + } +} + +impl Serialize for [T; N] + where T: Serialize { .. } + +impl Serialize for (T, U) + where T: Serialize, U: Serialize { .. } + +fn main() { + let data = (1, [2, 3, 4]); + assert(data.serialize().len(), 4); +} +``` + +Note that if there is any over or underflow the types will fail to unify: + +#include_code underflow-example test_programs/compile_failure/arithmetic_generics_underflow/src/main.nr rust + +This also applies if there is underflow in an intermediate calculation: + +#include_code intermediate-underflow-example test_programs/compile_failure/arithmetic_generics_intermediate_underflow/src/main.nr rust diff --git a/noir/noir-repo/docs/docs/noir/standard_library/meta/function_def.md b/noir/noir-repo/docs/docs/noir/standard_library/meta/function_def.md index 5657e05fff7..7fae5fc381a 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/meta/function_def.md +++ b/noir/noir-repo/docs/docs/noir/standard_library/meta/function_def.md @@ -7,6 +7,14 @@ a function definition in the source program. ## Methods +### add_attribute + +#include_code add_attribute noir_stdlib/src/meta/function_def.nr rust + +Adds an attribute to the function. This is only valid +on functions in the current crate which have not yet been resolved. +This means any functions called at compile-time are invalid targets for this method. + ### body #include_code body noir_stdlib/src/meta/function_def.nr rust @@ -21,6 +29,18 @@ This means any functions called at compile-time are invalid targets for this met Returns true if this function has a custom attribute with the given name. +### is_unconstrained + +#include_code is_unconstrained noir_stdlib/src/meta/function_def.nr rust + +Returns true if this function is unconstrained. + +### module + +#include_code module noir_stdlib/src/meta/function_def.nr rust + +Returns the module where the function is defined. + ### name #include_code name noir_stdlib/src/meta/function_def.nr rust @@ -65,3 +85,19 @@ each parameter pattern to be a syntactically valid parameter. Mutates the function's return type to a new type. This is only valid on functions in the current crate which have not yet been resolved. This means any functions called at compile-time are invalid targets for this method. + +### set_return_public + +#include_code set_return_public noir_stdlib/src/meta/function_def.nr rust + +Mutates the function's return visibility to public (if `true` is given) or private (if `false` is given). +This is only valid on functions in the current crate which have not yet been resolved. +This means any functions called at compile-time are invalid targets for this method. + +### set_unconstrained + +#include_code set_unconstrained noir_stdlib/src/meta/function_def.nr rust + +Mutates the function to be unconstrained (if `true` is given) or not (if `false` is given). +This is only valid on functions in the current crate which have not yet been resolved. +This means any functions called at compile-time are invalid targets for this method. \ No newline at end of file diff --git a/noir/noir-repo/docs/docs/noir/standard_library/meta/module.md b/noir/noir-repo/docs/docs/noir/standard_library/meta/module.md index 870e366461c..de042760d51 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/meta/module.md +++ b/noir/noir-repo/docs/docs/noir/standard_library/meta/module.md @@ -8,6 +8,14 @@ declarations in the source program. ## Methods +### add_item + +#include_code add_item noir_stdlib/src/meta/module.nr rust + +Adds a top-level item (a function, a struct, a global, etc.) to the module. +Adding multiple items in one go is also valid if the `Quoted` value has multiple items in it. +Note that the items are type-checked as if they are inside the module they are being added to. + ### name #include_code name noir_stdlib/src/meta/module.nr rust diff --git a/noir/noir-repo/docs/docs/noir/standard_library/meta/quoted.md b/noir/noir-repo/docs/docs/noir/standard_library/meta/quoted.md index bf79f2e5d9f..ac075d96648 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/meta/quoted.md +++ b/noir/noir-repo/docs/docs/noir/standard_library/meta/quoted.md @@ -50,6 +50,12 @@ stream doesn't parse to a type or if the type isn't a valid type in scope. #include_code implements_example test_programs/compile_success_empty/comptime_type/src/main.nr rust +### tokens + +#include_code tokens noir_stdlib/src/meta/quoted.nr rust + +Returns a slice of the individual tokens that form this token stream. + ## Trait Implementations ```rust diff --git a/noir/noir-repo/docs/docs/noir/standard_library/meta/struct_def.md b/noir/noir-repo/docs/docs/noir/standard_library/meta/struct_def.md index 95e377dffd4..c088e538fc9 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/meta/struct_def.md +++ b/noir/noir-repo/docs/docs/noir/standard_library/meta/struct_def.md @@ -7,6 +7,30 @@ This type corresponds to `struct Name { field1: Type1, ... }` items in the sourc ## Methods +### add_attribute + +#include_code add_attribute noir_stdlib/src/meta/struct_def.nr rust + +Adds an attribute to the struct. + +### add_generic + +#include_code add_generic noir_stdlib/src/meta/struct_def.nr rust + +Adds an generic to the struct. Returns the new generic type. +Errors if the given generic name isn't a single identifier or if +the struct already has a generic with the same name. + +This method should be used carefully, if there is existing code referring +to the struct type it may be checked before this function is called and +see the struct with the original number of generics. This method should +thus be preferred to use on code generated from other macros and structs +that are not used in function signatures. + +Example: + +#include_code add-generic-example test_programs/compile_success_empty/comptime_struct_definition/src/main.nr rust + ### as_type #include_code as_type noir_stdlib/src/meta/struct_def.nr rust @@ -44,6 +68,27 @@ comptime fn example(foo: StructDefinition) { Returns each field of this struct as a pair of (field name, field type). +### has_named_attribute + +#include_code has_named_attribute noir_stdlib/src/meta/struct_def.nr rust + +Returns true if this struct has a custom attribute with the given name. + +### module + +#include_code module noir_stdlib/src/meta/struct_def.nr rust + +Returns the module where the struct is defined. + +### name + +#include_code name noir_stdlib/src/meta/struct_def.nr rust + +Returns the name of this struct + +Note that the returned quoted value will be just the struct name, it will +not be the full path to the struct, nor will it include any generics. + ### set_fields #include_code set_fields noir_stdlib/src/meta/struct_def.nr rust diff --git a/noir/noir-repo/docs/docs/noir/standard_library/meta/typ.md b/noir/noir-repo/docs/docs/noir/standard_library/meta/typ.md index 0b6f8d5f77d..1334092a9fa 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/meta/typ.md +++ b/noir/noir-repo/docs/docs/noir/standard_library/meta/typ.md @@ -5,6 +5,30 @@ title: Type `std::meta::typ` contains methods on the built-in `Type` type used for representing a type in the source program. +## Functions + +#include_code fresh_type_variable noir_stdlib/src/meta/typ.nr rust + +Creates and returns an unbound type variable. This is a special kind of type internal +to type checking which will type check with any other type. When it is type checked +against another type it will also be set to that type. For example, if `a` is a type +variable and we have the type equality `(a, i32) = (u8, i32)`, the compiler will set +`a` equal to `u8`. + +Unbound type variables will often be rendered as `_` while printing them. Bound type +variables will appear as the type they are bound to. + +This can be used in conjunction with functions which internally perform type checks +such as `Type::implements` or `Type::get_trait_impl` to potentially grab some of the types used. + +Note that calling `Type::implements` or `Type::get_trait_impl` on a type variable will always +fail. + +Example: + +#include_code serialize-setup test_programs/compile_success_empty/comptime_type/src/main.nr rust +#include_code fresh-type-variable-example test_programs/compile_success_empty/comptime_type/src/main.nr rust + ## Methods ### as_array diff --git a/noir/noir-repo/noir_stdlib/src/cmp.nr b/noir/noir-repo/noir_stdlib/src/cmp.nr index b7f473429a7..521604a4e20 100644 --- a/noir/noir-repo/noir_stdlib/src/cmp.nr +++ b/noir/noir-repo/noir_stdlib/src/cmp.nr @@ -11,7 +11,13 @@ trait Eq { comptime fn derive_eq(s: StructDefinition) -> Quoted { let signature = quote { fn eq(_self: Self, _other: Self) -> bool }; let for_each_field = |name| quote { (_self.$name == _other.$name) }; - let body = |fields| fields; + let body = |fields| { + if s.fields().len() == 0 { + quote { true } + } else { + fields + } + }; crate::meta::make_trait_impl(s, quote { Eq }, signature, for_each_field, quote { & }, body) } // docs:end:derive_eq diff --git a/noir/noir-repo/noir_stdlib/src/meta/function_def.nr b/noir/noir-repo/noir_stdlib/src/meta/function_def.nr index cbbbfb2f901..5ce3dbeabff 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/function_def.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/function_def.nr @@ -1,4 +1,9 @@ impl FunctionDefinition { + #[builtin(function_def_add_attribute)] + // docs:start:add_attribute + fn add_attribute(self, attribute: str) {} + // docs:end:add_attribute + #[builtin(function_def_body)] // docs:start:body fn body(self) -> Expr {} @@ -9,6 +14,16 @@ impl FunctionDefinition { fn has_named_attribute(self, name: Quoted) -> bool {} // docs:end:has_named_attribute + #[builtin(function_def_is_unconstrained)] + // docs:start:is_unconstrained + fn is_unconstrained(self) -> bool {} + // docs:end:is_unconstrained + + #[builtin(function_def_module)] + // docs:start:module + fn module(self) -> Module {} + // docs:end:module + #[builtin(function_def_name)] // docs:start:name fn name(self) -> Quoted {} @@ -38,4 +53,14 @@ impl FunctionDefinition { // docs:start:set_return_type fn set_return_type(self, return_type: Type) {} // docs:end:set_return_type + + #[builtin(function_def_set_return_public)] + // docs:start:set_return_public + fn set_return_public(self, public: bool) {} + // docs:end:set_return_public + + #[builtin(function_def_set_unconstrained)] + // docs:start:set_unconstrained + fn set_unconstrained(self, value: bool) {} + // docs:end:set_unconstrained } diff --git a/noir/noir-repo/noir_stdlib/src/meta/module.nr b/noir/noir-repo/noir_stdlib/src/meta/module.nr index b3f76812b8a..bee6612e1bf 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/module.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/module.nr @@ -1,4 +1,9 @@ impl Module { + #[builtin(module_add_item)] + // docs:start:add_item + fn add_item(self, item: Quoted) {} + // docs:end:add_item + #[builtin(module_has_named_attribute)] // docs:start:has_named_attribute fn has_named_attribute(self, name: Quoted) -> bool {} diff --git a/noir/noir-repo/noir_stdlib/src/meta/quoted.nr b/noir/noir-repo/noir_stdlib/src/meta/quoted.nr index 9fd1e9026ba..3fab43359c1 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/quoted.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/quoted.nr @@ -3,24 +3,29 @@ use crate::option::Option; impl Quoted { #[builtin(quoted_as_expr)] -// docs:start:as_expr + // docs:start:as_expr fn as_expr(self) -> Option {} // docs:end:as_expr #[builtin(quoted_as_module)] -// docs:start:as_module + // docs:start:as_module fn as_module(self) -> Option {} // docs:end:as_module #[builtin(quoted_as_trait_constraint)] -// docs:start:as_trait_constraint + // docs:start:as_trait_constraint fn as_trait_constraint(self) -> TraitConstraint {} // docs:end:as_trait_constraint #[builtin(quoted_as_type)] -// docs:start:as_type + // docs:start:as_type fn as_type(self) -> Type {} // docs:end:as_type + + #[builtin(quoted_tokens)] + // docs:start:tokens + fn tokens(self) -> [Quoted] {} + // docs:end:tokens } impl Eq for Quoted { diff --git a/noir/noir-repo/noir_stdlib/src/meta/struct_def.nr b/noir/noir-repo/noir_stdlib/src/meta/struct_def.nr index 1ca1b6a3925..5db720b91d3 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/struct_def.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/struct_def.nr @@ -1,24 +1,49 @@ impl StructDefinition { + #[builtin(struct_def_add_attribute)] + // docs:start:add_attribute + fn add_attribute(self, attribute: str) {} + // docs:end:add_attribute + + #[builtin(struct_def_add_generic)] + // docs:start:add_generic + fn add_generic(self, generic_name: str) -> Type {} + // docs:end:add_generic + /// Return a syntactic version of this struct definition as a type. /// For example, `as_type(quote { type Foo { ... } })` would return `Foo` #[builtin(struct_def_as_type)] -// docs:start:as_type + // docs:start:as_type fn as_type(self) -> Type {} // docs:end:as_type + #[builtin(struct_def_has_named_attribute)] + // docs:start:has_named_attribute + fn has_named_attribute(self, name: Quoted) -> bool {} + // docs:end:has_named_attribute + /// Return each generic on this struct. #[builtin(struct_def_generics)] -// docs:start:generics + // docs:start:generics fn generics(self) -> [Type] {} // docs:end:generics /// Returns (name, type) pairs of each field in this struct. Each type is as-is /// with any generic arguments unchanged. #[builtin(struct_def_fields)] -// docs:start:fields + // docs:start:fields fn fields(self) -> [(Quoted, Type)] {} // docs:end:fields + #[builtin(struct_def_module)] + // docs:start:module + fn module(self) -> Module {} + // docs:end:module + + #[builtin(struct_def_name)] + // docs:start:name + fn name(self) -> Quoted {} + // docs:end:name + /// Sets the fields of this struct to the given fields list. /// All existing fields of the struct will be overridden with the given fields. /// Each element of the fields list corresponds to the name and type of a field. diff --git a/noir/noir-repo/noir_stdlib/src/meta/typ.nr b/noir/noir-repo/noir_stdlib/src/meta/typ.nr index 12dc91a4925..71bd6fd7f1c 100644 --- a/noir/noir-repo/noir_stdlib/src/meta/typ.nr +++ b/noir/noir-repo/noir_stdlib/src/meta/typ.nr @@ -1,6 +1,11 @@ use crate::cmp::Eq; use crate::option::Option; +#[builtin(fresh_type_variable)] +// docs:start:fresh_type_variable +pub fn fresh_type_variable() -> Type {} +// docs:end:fresh_type_variable + impl Type { #[builtin(type_as_array)] // docs:start:as_array diff --git a/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_intermediate_underflow/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_intermediate_underflow/Nargo.toml new file mode 100644 index 00000000000..0c5d98628a1 --- /dev/null +++ b/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_intermediate_underflow/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "arithmetic_generics_intermediate_underflow" +type = "bin" +authors = [""] +compiler_version = ">=0.33.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_intermediate_underflow/src/main.nr b/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_intermediate_underflow/src/main.nr new file mode 100644 index 00000000000..58cf2f648e5 --- /dev/null +++ b/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_intermediate_underflow/src/main.nr @@ -0,0 +1,32 @@ +// docs:start:intermediate-underflow-example +fn main() { + // From main it looks like there's nothing sketchy going on + seems_fine([]); +} + +// Since `seems_fine` says it can receive and return any length N +fn seems_fine(array: [Field; N]) -> [Field; N] { + // But inside `seems_fine` we pop from the array which + // requires the length to be greater than zero. + + // error: Could not determine array length `(0 - 1)` + push_zero(pop(array)) +} + +fn pop(array: [Field; N]) -> [Field; N - 1] { + let mut result: [Field; N - 1] = std::mem::zeroed(); + for i in 0..N { + result[i] = array[i]; + } + result +} + +fn push_zero(array: [Field; N]) -> [Field; N + 1] { + let mut result: [Field; N + 1] = std::mem::zeroed(); + for i in 0..N { + result[i] = array[i]; + } + // index N is already zeroed + result +} +// docs:end:intermediate-underflow-example diff --git a/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_underflow/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_underflow/Nargo.toml new file mode 100644 index 00000000000..f024f4c3b59 --- /dev/null +++ b/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_underflow/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "arithmetic_generics_underflow" +type = "bin" +authors = [""] +compiler_version = ">=0.33.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_underflow/src/main.nr b/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_underflow/src/main.nr new file mode 100644 index 00000000000..4df83ac56e0 --- /dev/null +++ b/noir/noir-repo/test_programs/compile_failure/arithmetic_generics_underflow/src/main.nr @@ -0,0 +1,14 @@ +// docs:start:underflow-example +fn pop(array: [Field; N]) -> [Field; N - 1] { + let mut result: [Field; N - 1] = std::mem::zeroed(); + for i in 0..N { + result[i] = array[i]; + } + result +} + +fn main() { + // error: Could not determine array length `(0 - 1)` + pop([]); +} +// docs:end:underflow-example diff --git a/noir/noir-repo/test_programs/compile_success_empty/attributes_struct/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/attributes_struct/src/main.nr index 0bad42aee57..25c9402035c 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/attributes_struct/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/attributes_struct/src/main.nr @@ -6,3 +6,16 @@ struct SomeStruct { } fn main() {} + +// Check that add_attribute and has_named_attribute work well + +#[add_attribute] +struct Foo { + +} + +fn add_attribute(s: StructDefinition) { + assert(!s.has_named_attribute(quote { foo })); + s.add_attribute("foo"); + assert(s.has_named_attribute(quote { foo })); +} diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_function_definition/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_function_definition/src/main.nr index 8528bbce153..62f119cc0c0 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/comptime_function_definition/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_function_definition/src/main.nr @@ -3,7 +3,7 @@ use std::meta::type_of; struct Foo { x: Field, field: Field } #[function_attr] -fn foo(w: i32, y: Field, Foo { x, field: some_field }: Foo, mut a: bool, (b, c): (i32, i32)) -> i32 { +pub fn foo(w: i32, y: Field, Foo { x, field: some_field }: Foo, mut a: bool, (b, c): (i32, i32)) -> i32 { let _ = (w, y, x, some_field, a, b, c); 1 } @@ -57,3 +57,32 @@ comptime fn mutate_add_one(f: FunctionDefinition) { fn main() { assert_eq(add_one(41), 42); } + +contract some_contract { + // No pub on the return type is an error + #[super::set_pub_return] + pub fn bar() -> Field { + 1 + } +} + +fn set_pub_return(f: FunctionDefinition) { + f.set_return_public(true); +} + +mod foo { + #[attr] + pub fn some() {} + + fn attr(f: FunctionDefinition) { + assert_eq(f.module().name(), quote { foo }); + + assert(!f.is_unconstrained()); + + f.set_unconstrained(true); + assert(f.is_unconstrained()); + + f.set_unconstrained(false); + assert(!f.is_unconstrained()); + } +} diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_module/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_module/src/main.nr index 5722d42ca26..baf45c517ed 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/comptime_module/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_module/src/main.nr @@ -1,8 +1,8 @@ #[outer_attribute] mod foo { #![some_attribute] - fn x() {} - fn y() {} + pub fn x() {} + pub fn y() {} } contract bar {} @@ -13,7 +13,7 @@ mod another_module {} #[outer_attribute_func] mod yet_another_module { #![super::inner_attribute_func] - fn foo() {} + pub fn foo() {} } #[outer_attribute_separate_module] @@ -25,14 +25,16 @@ fn increment_counter() { counter += 1; } -fn outer_attribute_func(m: Module) { +fn outer_attribute_func(m: Module) -> Quoted { assert_eq(m.name(), quote { yet_another_module }); increment_counter(); + quote { pub fn generated_outer_function() {} } } -fn inner_attribute_func(m: Module) { +fn inner_attribute_func(m: Module) -> Quoted { assert_eq(m.name(), quote { yet_another_module }); increment_counter(); + quote { pub fn generated_inner_function() {} } } fn outer_attribute_separate_module(m: Module) { @@ -40,6 +42,22 @@ fn outer_attribute_separate_module(m: Module) { increment_counter(); } +struct Foo {} + +#[add_function] +mod add_to_me { + fn add_to_me_function() {} +} + +fn add_function(m: Module) { + m.add_item( + quote { pub fn added_function() -> super::Foo { + add_to_me_function(); + super::Foo {} + } } + ); +} + fn main() { comptime { @@ -68,6 +86,11 @@ fn main() { } assert_eq(counter, 4); + + yet_another_module::generated_outer_function(); + yet_another_module::generated_inner_function(); + + let _ = add_to_me::added_function(); } // docs:start:as_module_example diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_type_definition/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/comptime_struct_definition/Nargo.toml similarity index 69% rename from noir/noir-repo/test_programs/compile_success_empty/comptime_type_definition/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/comptime_struct_definition/Nargo.toml index 099545a9e71..4495d27e028 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/comptime_type_definition/Nargo.toml +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_struct_definition/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "comptime_type_definition" +name = "comptime_struct_definition" type = "bin" authors = [""] compiler_version = ">=0.31.0" diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_struct_definition/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_struct_definition/src/main.nr new file mode 100644 index 00000000000..da2871a253d --- /dev/null +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_struct_definition/src/main.nr @@ -0,0 +1,50 @@ +#[my_comptime_fn] +struct MyType { + field1: [A; 10], + field2: (B, C), +} + +#[mutate_struct_fields] +struct I32AndField { + z: i8, +} + +comptime fn my_comptime_fn(typ: StructDefinition) { + let _ = typ.as_type(); + assert_eq(typ.generics().len(), 3); + assert_eq(typ.fields().len(), 2); + assert_eq(typ.name(), quote { MyType }); +} + +comptime fn mutate_struct_fields(s: StructDefinition) { + let fields = &[ + (quote[x], quote[i32].as_type()), + (quote[y], quote[Field].as_type()) + ]; + s.set_fields(fields); +} + +mod foo { + #[attr] + struct Foo {} + + comptime fn attr(s: StructDefinition) { + assert_eq(s.module().name(), quote { foo }); + } + + #[add_generic] + struct Bar {} + + // docs:start:add-generic-example + comptime fn add_generic(s: StructDefinition) { + assert_eq(s.generics().len(), 0); + let new_generic = s.add_generic("T"); + + let generics = s.generics(); + assert_eq(generics.len(), 1); + assert_eq(generics[0], new_generic); + } + // docs:end:add-generic-example +} + +fn main() {} 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 0b15c5605b3..c9307570c87 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 @@ -19,6 +19,18 @@ struct StructDoesNotImplementSomeTrait { } +// docs:start:serialize-setup +trait Serialize {} + +impl Serialize<1> for Field {} + +impl Serialize for [T; N] + where T: Serialize {} + +impl Serialize for (T, U) + where T: Serialize, U: Serialize {} +// docs:end:serialize-setup + fn main() { comptime { @@ -115,6 +127,29 @@ fn main() { let str_type = quote { str<10> }.as_type(); let constant = str_type.as_str().unwrap(); assert_eq(constant.as_constant().unwrap(), 10); + + // Check std::meta::typ::fresh_type_variable + // docs:start:fresh-type-variable-example + let typevar1 = std::meta::typ::fresh_type_variable(); + let constraint = quote { Serialize<$typevar1> }.as_trait_constraint(); + let field_type = quote { Field }.as_type(); + + // Search for a trait impl (binding typevar1 to 1 when the impl is found): + assert(field_type.implements(constraint)); + + // typevar1 should be bound to the "1" generic now: + assert_eq(typevar1.as_constant().unwrap(), 1); + + // If we want to do the same with a different type, we need to + // create a new type variable now that `typevar1` is bound + let typevar2 = std::meta::typ::fresh_type_variable(); + let constraint = quote { Serialize<$typevar2> }.as_trait_constraint(); + let array_type = quote { [(Field, Field); 5] }.as_type(); + assert(array_type.implements(constraint)); + + // Now typevar2 should be bound to the serialized pair size 2 times the array length 5 + assert_eq(typevar2.as_constant().unwrap(), 10); + // docs:end:fresh-type-variable-example } } diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_type_definition/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_type_definition/src/main.nr deleted file mode 100644 index aca8d067dde..00000000000 --- a/noir/noir-repo/test_programs/compile_success_empty/comptime_type_definition/src/main.nr +++ /dev/null @@ -1,26 +0,0 @@ -fn main() {} - -#[my_comptime_fn] -struct MyType { - field1: [A; 10], - field2: (B, C), -} - -#[mutate_struct_fields] -struct I32AndField { - z: i8, -} - -comptime fn my_comptime_fn(typ: StructDefinition) { - let _ = typ.as_type(); - assert_eq(typ.generics().len(), 3); - assert_eq(typ.fields().len(), 2); -} - -comptime fn mutate_struct_fields(s: StructDefinition) { - let fields = &[ - (quote[x], quote[i32].as_type()), - (quote[y], quote[Field].as_type()) - ]; - s.set_fields(fields); -} diff --git a/noir/noir-repo/test_programs/compile_success_empty/references_aliasing/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/references_aliasing/src/main.nr index 0d96bc2a734..d3e4257851b 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/references_aliasing/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/references_aliasing/src/main.nr @@ -5,6 +5,7 @@ fn main() { assert(*xref == 101); regression_2445(); + single_alias_inside_loop(); } fn increment(mut r: &mut Field) { @@ -26,3 +27,15 @@ fn regression_2445() { assert(**array[0] == 2); assert(**array[1] == 2); } + +fn single_alias_inside_loop() { + let mut var = 0; + let ref = &mut &mut var; + + for _ in 0..1 { + **ref = 2; + } + + assert(var == 2); + assert(**ref == 2); +} diff --git a/noir/noir-repo/test_programs/execution_success/derive/src/main.nr b/noir/noir-repo/test_programs/execution_success/derive/src/main.nr index 5ec2fb32a79..b32612831d7 100644 --- a/noir/noir-repo/test_programs/execution_success/derive/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/derive/src/main.nr @@ -35,6 +35,9 @@ struct MyOtherOtherStruct { x: T, } +#[derive(Eq, Default, Hash, Ord)] +struct EmptyStruct { } + fn main() { let s = MyStruct { my_field: 1 }; s.do_nothing(); @@ -53,6 +56,9 @@ fn main() { let mut hasher = TestHasher { result: 0 }; o1.hash(&mut hasher); assert_eq(hasher.finish(), 12 + 24 + 54); + + let empty = EmptyStruct {}; + assert_eq(empty, empty); } struct TestHasher { 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 5bdebb476be..00000000000 --- a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Prover.toml +++ /dev/null @@ -1,575 +0,0 @@ -key_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" -proof = [ - "0x0000000000000000000000000000000000000000000000000000000000000040", - "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", - "0x0000000000000000000000000000006cf7dd96d7636fda5953191b1ad776d491", - "0x00000000000000000000000000000000001633d881a08d136e834cb13a28fcc6", - "0x00000000000000000000000000000001254956cff6908b069fca0e6cf1c47eb1", - "0x000000000000000000000000000000000006f4d4dd3890e997e75e75886bf8f7", - "0x0000000000000000000000000000006cf7dd96d7636fda5953191b1ad776d491", - "0x00000000000000000000000000000000001633d881a08d136e834cb13a28fcc6", - "0x00000000000000000000000000000001254956cff6908b069fca0e6cf1c47eb1", - "0x000000000000000000000000000000000006f4d4dd3890e997e75e75886bf8f7", - "0x000000000000000000000000000000f968b227a358a305607f3efc933823d288", - "0x00000000000000000000000000000000000eaf8adb390375a76d95e918b65e08", - "0x000000000000000000000000000000bb34b4b447aae56f5e24f81c3acd6d547f", - "0x00000000000000000000000000000000002175d012746260ebcfe339a91a81e1", - "0x000000000000000000000000000000286fcda0e28617c86e195005b9f2efc555", - "0x00000000000000000000000000000000000dc409eb684b23f6a97175bcb9b486", - "0x000000000000000000000000000000e8de6a193cd36414f598bc7c48d67c3b59", - "0x00000000000000000000000000000000002a8a791544cad8c712de871e3de50a", - "0x000000000000000000000000000000d6f1e64b562df0f17ecc6aa46392f8d5a3", - "0x00000000000000000000000000000000000aac977763f33fd6a360ccc50a827a", - "0x000000000000000000000000000000899fa957f5597c6419e3ead9843d21d917", - "0x000000000000000000000000000000000016c4611846952bd6833c35fb11c0da", - "0x013dbfbfbfb2ae7d524edb15343e551d9510b3116223baaa67312d17652f2fb1", - "0x2f268eb3217ef1ac66016aa14d43033f932335371795b5e6dcb0c87c8ad0d050", - "0x2d5dbd52e00ae837e9868289fbe9057f16ea5b76c7e362603e8883f0de4b3e94", - "0x0e357b6a266c20d5e546c2931475eb044d7e75e08ec31b5e8623aec30f964323", - "0x0a9ace4dea44d0a2e8d12d495a683f508714356656aea3882436b729ead24165", - "0x0c17102a98ccb76faf0f78d669ee9cfb694849896787c985225d92e1af3cab35", - "0x09cc7cb719deb139c84fd9fa273e862a1b5d1cec2501c6cd8ba3c37ca06ac07f", - "0x15a0369f3f95d53687dfe79483baf75597d8b281fe0595caf1f7c9ccf99d985e", - "0x17fb53a42b3d1fa5d26ab19dfcc0d74d1781cee0be98dcc492c22e8f3442c4db", - "0x291d6810fc6afc5c2254fd283843a74c85a77275eee3049ea8ed9c88e02a99b8", - "0x0ad40d1627c31247dfb894584a71f8599cfcb85afe84b20186fc07fccae1aa4a", - "0x251cd908fb4e9fe88660f2303f8d7e4d7886da32fddc0319a842b99543659c0b", - "0x1885bdea3dd82085ca67502ebec8ad87213493e18a06cfa27e2c69810481b4a7", - "0x239ab5ba86866bc6705091f82a6a29444dc76b0e7d94cede7eb745cce36ab2cf", - "0x088d29a03baa491845d152124189dfb8bf70ba9bf1fb00c379199dbb0195c663", - "0x18c9fbe3227988d2da599eba82d60f4de25b442b663585fdc611e37305fa77fc", - "0x010242ae641a8cc4d06b5d24e38d9fa6254f981e28f238ccf6aad580f780d3f5", - "0x00128d34b122e84d7e23276b1f13f5789a562e82c727e9ffcfd7bbaccbe69e04", - "0x0776defaf478bfea4db2698542314e27213f63c96e41f98d4d82a47ed6fab55d", - "0x273014a360eaaa493e398df82f18d9cae37f4b6c0ead20100cad3f5491805298", - "0x2b13528eb9ab6fa705f2b48c9ec6ce054ac984e3adf17d4d73431e8456bf4a3c", - "0x22dafe1d63e39cd2effb236da2e131ee1c8cf4049ce504431dcaf98f75c47ad8", - "0x1afb5bc7eb8d30d807101357bb290f9c3113523f4aacc1154a27b075e46a4fa4", - "0x0782dd7df679163e5f0c126abc901d00f3d7d0856b4c02a199ab691ecd7566e6", - "0x2e556c722c99a84a09ffdcc719178277f8e6c9e31a4769270e3b522b944b8ea2", - "0x1be933a48dca8ef26202d3f135998ac8bed6947020b7447ffb6033b0e37f2065", - "0x2d8ebae210848de2464f5435f1fd4b5467ee938910d7779002614943060bbb32", - "0x2da854bbee38a94a6a9c2c85dd05bb4c879173720b67f93f78b9de93cdb427b0", - "0x0fa2649472af2e79489c466b58002f8f284f953085ac0a98dfabee85b78f63cf", - "0x304a09437636026ef0746c4b8ac1ca0ff250c5630fb5bd03ddafddd7cbde850e", - "0x0c83bb3c6ee0faa1646ee4d8dd83f67ec98e5d63ac802f7bdebfcdf21dee62f1", - "0x229d7e4524b30c18a6b94f0054e6d2ea8eb2396f58f9c808d2c9f991e2be2399", - "0x1265bf5e1aaddeae09242b1435e2f8f9e7487bf76a0461752777f6ea1ff75ad6", - "0x2f32f53281b7a363d6bec84ca21c71c3206d906b036e8b36b0702780e3b1b870", - "0x017fb18c9aef4d6d2bc99f5d7f9a002c8921fcd7c7ba69bf05930b55c2829cb7", - "0x2ec761c02ef6f2eefb7c9b2d6df71795d0ce0820f86797e2e11415cb5b122f22", - "0x2b1722960f42a1b40ffae3e4b9419fc8ff5cb8139a2c7e89af332ba2e95c1b5f", - "0x2dafa15594da2318245475c77eae3712429226b3005852e70f567efff0a7d79a", - "0x2ed44d7e3d5f44ac8f7c144ee0ba9d369c82428827c19b010384708bbc52a3f9", - "0x2777eedda697c7f90aee44fa97cfe62596d16c43fa3545b48d622023ca7a446a", - "0x1a47a5c1b0f41905aa0bad6248be8c7887ddea3ad9dfc8462b23a95b073c8a49", - "0x093656d571e84ac676a265dd509c98513039552b7a24e001b003ca618cc4ea5c", - "0x15c901e8a7ff0f1ae1989b5cfb687975c16716a8014a4052d527d4db4ecbaeb4", - "0x08bfa20e83096b0be58e4c96232510c8ef9824c0a62b91ffcc4592b217753a72", - "0x021913efbdfbc73aa5f4a97c79f352ac61f71248947f5eb5713c1b107c632703", - "0x00df89625aef270fab2a8c33ba742e1375423f4cfb3f63514ae748e004bb8cf4", - "0x2455f76c8ee59e93cbe7fe192cf0f766e1399617cabfa230cf27ca2a18cd58d5", - "0x150c3e56ea4f6442ed6b11030c98682a8f5e3c9cd6fd18949254a7c79b3cb5b6", - "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", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x01e89c6fe644aea7f63301278dbdb4ea29cf4d33f8b0cdcd79cb106e0bf0a753", - "0x2d49d23421e253903b8a5d0911642b9ce218cef4e350cf8689704eb1f3ae38d4", - "0x072956ca447343d788791fee1ef222f280048ad4aefb6cb7bc96b538f482f525", - "0x168176bf15c8ca63457acf05efbe54af452ea41f935ab82c2a96fedde10ba52f", - "0x20a13690f13491f7f3b756a1dc3b69a3f96d78355c70289583032a593bfc87bc", - "0x273e0a32ab3ef0d3f179b62520b31015ccfc8b53c76a1bb323b41e40ff954596", - "0x28019d4b05546b44e35d5dc74375b75dabb6fae49a07381605c60423c6163d26", - "0x10beda0b8dd484c63f0937820e2c7e9be832a0031efe3557631608895255ca5f", - "0x095a8f04a901526e4d70b1560bfff29b5a3c30347725d1e420c1b30ee2bf8a1c", - "0x1fb742e863a5c76262ffec93b3351405b0840b326fa5fffd73f40abcd5f05f05", - "0x11fa63cfcb2e603fe4e4668d75f05a2cf22650b84a91d1753e83f0e7ae83b4ad", - "0x2872e3d3c431a8b7ee4cec1c2a999a42c40ae33382fbba80a6d4c1a39b2d57a3", - "0x17e8c2a5f809f9935d7c6d7cb2f8859a513864b53f53de3d2a14c74cd690bd1a", - "0x20a552298d691393ae401382b3015689231ad988d3eb0521d414dcd2e8781053", - "0x183eb6bca59a141b4e8136179a258272ec9c25ec80bdb0458b6880c711707a28", - "0x03cd147a2a4c8dc272f3e240b8b0090d45e994e5fd40e07a54f6765795cd5ef8", - "0x082b135b3a20da4c766242b4258e27dbc050e4b8958bb15431626f2eeed9bd2b", - "0x28c894a6a719a32fe8d78ded46bc685ba035e5579c88fbc5bcbc0f09d8c5268b", - "0x06418cceff50837f923e63a37c2c534d13d9f59793c3aa6274813baa64d1899e", - "0x2b4a27b672f85c4fc697605da213de8b950a629602c5b8c6403e6c1c1065388a", - "0x0e2b817c6a79d6d1027f0376fb26ec81a140a4402e2dcdff6152cf01f2f4dbf9", - "0x2ae0fbce87dc53f0ff5473117e1c49a8197a14f8eaaec00cb5b10f94e844111f", - "0x2368004a1dee06f505e75ada3e9f8cc4c801f6a2068620da51ba11f537453835", - "0x2009df8e6f49f67dcaecb93e4a9ef81aaff096136d26f0fe691e14cd580c47da", - "0x2e512617136e8da2817856e57f13087a75fcc512faefc6d4b2eedd73c58a9b35", - "0x2848fcd535bd7c8017ca331a14919aa492ed05b04e9d0745480d291205eac8dc", - "0x19bb0990cb37f3a8f6c3db78219b07d6accd08e889586660e92dd6000755f09a", - "0x15520c8158b2e36c40c5fa46d5281c45d3df2c7f5d974a1f9549bfca6cbceaea", - "0x0e285f4df658d99922c286c5a253d6f6f37aa6c52d7a0fc1a20f3e6da9df23e1", - "0x0f9cd4667f4c1e86f83eda9e752a05c0cc630b0827a93a68322fa258dffb0f24", - "0x12d8b0dbbea3dccfe5d2dd090daf8ab4d2fac74fada9c49875b0c9122663a8ad", - "0x2e8c814d93f027ecff08c4e58555aadfc0f9ec3889eff2150f2b5bb6c557add0", - "0x013516a1456c5831aba87e4057878f6f3f18471e0674fd1e89be3e18351ec394", - "0x14418aa79dc84fd791d5638bdc103786ef8181a714ee8e022d3a1e792cbc7959", - "0x14418aa79dc84fd791d5638bdc103786ef8181a714ee8e022d3a1e792cbc7959", - "0x25c5e6c96a39bb36e19106d4049b675f0279084cc757c4e2acf6e497c61056a2", - "0x231aaafcf2a4c6fd8da18ce5ae5b33790f2c306a2692c6383c9a0787c50ac269", - "0x0a5f7665f0997081f9b38ec64e9a18542ac3a9648060f8cc720fc04669224730", - "0x0f1c9d9d1ac6f62825c6038117ed30540be434e8fd2d88150dcd4fece39b335a", - "0x1308871c8fcb09f07e5257f5cc5678d98842a8d18b2af09b5132d9af3cb1893e", - "0x28801985290dac4eba72ed01ee06fe88f6fc533dc1a46bd86e2d35be8021b042", - "0x14407f38cfba3cc61fca173b41133ab05a1c176caf8bb597588b01817e9eeaa3", - "0x0ea1a9f6f95f6193e512a7bd3db0c147f66687662934aed53cb657935b1e4eb9", - "0x1bc4ab6eacd61b5fd9e414b0186ef5deaadaf59aa9e53cb8d8812255baa28109", - "0x00000000000000000000000000000093a4da68a2fac0ee94841efdfc57eb748c", - "0x00000000000000000000000000000000001c22f1f5f927bee6adb649cc132391", - "0x0000000000000000000000000000003d0c2acea76c551f58876b3c35f19f345a", - "0x00000000000000000000000000000000002e94fded0a0b7f4fd1c882fd2a4e52", - "0x00000000000000000000000000000022e23b6fa0f72844bf8f60ea140cca5663", - "0x000000000000000000000000000000000013380f284bf3cb98b9a7cbae7d702b", - "0x000000000000000000000000000000942a13cf93056815c3f7439c9eed0a103e", - "0x00000000000000000000000000000000002be14bec02c6dae4625d32866de4fc", - "0x000000000000000000000000000000e2a2c75dc664c12695b4f7795c61f92669", - "0x000000000000000000000000000000000000725da448f376bde6cf63bcf79463", - "0x000000000000000000000000000000f54eee585f8ab367dc66a587e1d4cdbd8c", - "0x0000000000000000000000000000000000071106624ae5623a070f0addc18433", - "0x000000000000000000000000000000d60352bea3b2adb311b1a3beb25acb8aed", - "0x00000000000000000000000000000000001965b7c781e33f94e90c743c7881ed", - "0x0000000000000000000000000000006458a2aa57539e2b192f9c3ed69f9fb674", - "0x00000000000000000000000000000000001fc9c667723a4e66d752c6b426d444", - "0x0000000000000000000000000000008d1ff1c5d59a463c5b46bcf52f41ad3c63", - "0x00000000000000000000000000000000001b3e73df070a35c49a03fab1c76e9b", - "0x0000000000000000000000000000001c17a62b6c0a7ab14de83391e06f780adb", - "0x000000000000000000000000000000000012c7fbe2591b9ae72dd526e4ed1d7f", - "0x000000000000000000000000000000a758fa0c72d6a93155cb18b3fcc7defd34", - "0x00000000000000000000000000000000000cea12961770ce7cb6f2a4aed009fe", - "0x000000000000000000000000000000ef6e9647803aac315fa6d287e0e66f4767", - "0x0000000000000000000000000000000000259a82b8d6c6015cc51d2681f26ad4", - "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", - "0x0000000000000000000000000000008152b373c87004bef7d2c55ec8c540b67f", - "0x00000000000000000000000000000000000a55be5fdcb0a0dce4976d7bb78b0c", - "0x000000000000000000000000000000f749ea03f04ac964706139b9d1db595ecb", - "0x000000000000000000000000000000000013218e14dae80c066b4e46e9309fb2", - "0x0000000000000000000000000000004bbd7f950c36ce69db39e2b234a9e3f9b0", - "0x00000000000000000000000000000000002a0c3994d892ca5ea26984abbb30fb", - "0x0000000000000000000000000000006c1b39306846620bd546ac2c897834f259", - "0x000000000000000000000000000000000020350b9f507d6e25961a11be3e494b", -] -public_inputs = [ - "0x0000000000000000000000000000000000000000000000000000000000000003", -] -verification_key = [ - "0x0000000000000000000000000000000000000000000000000000000000000040", - "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", - "0x000000000000000000000000000000ee40d90bea71fba7a412dd61fcf34e8ceb", - "0x0000000000000000000000000000000000140b0936c323fd2471155617b6af56", - "0x0000000000000000000000000000002b90071823185c5ff8e440fd3d73b6fefc", - "0x00000000000000000000000000000000002b6c10790a5f6631c87d652e059df4", - "0x00000000000000000000000000000029a17181c7934fc3fdbd352eac5cb521b9", - "0x00000000000000000000000000000000001f497cbf5284ff29a2d336e5991999", - "0x000000000000000000000000000000072bd9c0c6beda1fdee6d4ff0432ba9e1b", - "0x000000000000000000000000000000000013ea38a0bd2aa751a490a724fac818", - "0x000000000000000000000000000000c599f63dcd3edd49f08ae5c3141c1e3493", - "0x00000000000000000000000000000000002bdb36be0bea09950dd32a8ccf6fbc", - "0x00000000000000000000000000000047f27f29724e7f19eba0340256a0bd4b7d", - "0x00000000000000000000000000000000001c1c5ccf87a962129ca785f8f35120", - "0x000000000000000000000000000000c5c71efdae00679bbe4a95096e012b1817", - "0x000000000000000000000000000000000017a365de041e317817d0135f2b48e0", - "0x0000000000000000000000000000008ae711ac402f7848d719c93a89ba8d39f1", - "0x00000000000000000000000000000000002b6fb40ed8a1935226f4f9786a0499", - "0x0000000000000000000000000000002f03a71501d83de1da5715a4e9462d6198", - "0x00000000000000000000000000000000001644064443b8546f48eae693af47b8", - "0x00000000000000000000000000000083763ab1b6e8fe269b2fe4c7b9c448c08d", - "0x000000000000000000000000000000000021d7cc18c59676a8eeb47c0111c251", - "0x000000000000000000000000000000b5f937153073e03ea7d51a996e0ebc2e6b", - "0x000000000000000000000000000000000011ddd0e26457373eb06e0493177672", - "0x000000000000000000000000000000c5f6eb9f6fc8fa99811a4a88c74a6d018b", - "0x000000000000000000000000000000000025bcd07a0732c123567834f5109558", - "0x000000000000000000000000000000aeb08a0b1a4442189448b4e97490568146", - "0x000000000000000000000000000000000002a1744e4771705536a88f07e0f90f", - "0x000000000000000000000000000000b938568293bd0724b0ea76c2ec34c4a829", - "0x0000000000000000000000000000000000053296e8f3b9ad3af877dfa9c7c2a7", - "0x000000000000000000000000000000f0ca1db6323996eba26bdc86dafef9d10b", - "0x00000000000000000000000000000000001441a46c58af03d5645d52721d956a", - "0x0000000000000000000000000000008bbf8f884013c66c28ba09c2fbd573b656", - "0x0000000000000000000000000000000000206c391ca06fac27d1908e94570243", - "0x0000000000000000000000000000002d4f5aaed88ba4f79612d53b804ca8f194", - "0x00000000000000000000000000000000001674011c96392df08970fa6b7b4cb8", - "0x0000000000000000000000000000009f88297c1729d76c4d9306853598c91325", - "0x0000000000000000000000000000000000256f51adfcacc3c1e340be4d32d3e9", - "0x0000000000000000000000000000000ab9955eec0d74eb799afed2a802b24d75", - "0x00000000000000000000000000000000001fcbe43ea105b30d36ed0b21b03411", - "0x000000000000000000000000000000d66b1d5433f1aa5305cd1edce7c22de466", - "0x00000000000000000000000000000000002331546a256b8a3b751956806680d4", - "0x000000000000000000000000000000e97954ad6cd6f45fb15c91434121db4304", - "0x00000000000000000000000000000000002e20a97e09d50f227ced47e7a98250", - "0x0000000000000000000000000000001ebbc27eb9ebededefba79522eb58ae89b", - "0x0000000000000000000000000000000000090efa4974e566e81d1177b85a30be", - "0x0000000000000000000000000000005eafa070b9c9632404052642e3bc14f9fd", - "0x00000000000000000000000000000000001489068864102daca6a6b8bc4d448b", - "0x0000000000000000000000000000009ebc91aaaac036a6477cadbe54e8556dfd", - "0x00000000000000000000000000000000000ef6d835e2ed3343b95c82c8c54037", - "0x00000000000000000000000000000033b28b529dff46e93af4e7422530478e4a", - "0x000000000000000000000000000000000020a86c2f8591bf190bcddcc03c42fb", - "0x000000000000000000000000000000a9679d0acc088f7dc27bf6d866bcd2dda2", - "0x00000000000000000000000000000000002fb9d0d2d4099402bed74f738f64cc", - "0x00000000000000000000000000000023b09f876a29a061582848a8b9a5870c12", - "0x00000000000000000000000000000000001d5bb906f03f0d49e9c4791bc43af9", - "0x00000000000000000000000000000017aac9854ea240d8ec97bf760c4d4ba870", - "0x00000000000000000000000000000000000b227a556c414ada0dc75bb303e30e", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000009b624fa65d1a24b7f14a8f25f3789622af", - "0x000000000000000000000000000000000013d47bff8c630e847b70e2732fd3f0", - "0x00000000000000000000000000000061d21663e93132f32921075f4c936a84df", - "0x00000000000000000000000000000000001a74ca4e118fb480b9b999902989a3", -] 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 b60a47ccc7f..00000000000 --- a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/src/main.nr +++ /dev/null @@ -1,17 +0,0 @@ - -// This circuit aggregates a single Honk proof from `assert_statement_recursive`. -global SIZE_OF_PROOF_IF_LOGN_IS_28 : u32 = 439; -global HONK_IDENTIFIER : u32 = 1; -fn main( - verification_key: [Field; 128], - // 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 59758f4b972..dad0d37aba7 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion.rs @@ -5,7 +5,7 @@ use std::{ use async_lsp::ResponseError; use completion_items::{ - crate_completion_item, field_completion_item, simple_completion_item, + crate_completion_item, field_completion_item, simple_completion_item, snippet_completion_item, struct_field_completion_item, }; use convert_case::{Case, Casing}; @@ -15,11 +15,11 @@ use lsp_types::{CompletionItem, CompletionItemKind, CompletionParams, Completion use noirc_errors::{Location, Span}; use noirc_frontend::{ ast::{ - AsTraitPath, BlockExpression, CallExpression, ConstructorExpression, Expression, - ExpressionKind, ForLoopStatement, GenericTypeArgs, Ident, IfExpression, ItemVisibility, - Lambda, LetStatement, MemberAccessExpression, MethodCallExpression, NoirFunction, - NoirStruct, NoirTraitImpl, Path, PathKind, Pattern, Statement, TypeImpl, UnresolvedGeneric, - UnresolvedGenerics, UnresolvedType, UseTree, UseTreeKind, Visitor, + AsTraitPath, AttributeTarget, BlockExpression, CallExpression, ConstructorExpression, + Expression, ExpressionKind, ForLoopStatement, GenericTypeArgs, Ident, IfExpression, + ItemVisibility, Lambda, LetStatement, MemberAccessExpression, MethodCallExpression, + NoirFunction, NoirStruct, NoirTraitImpl, Path, PathKind, Pattern, Statement, TypeImpl, + UnresolvedGeneric, UnresolvedGenerics, UnresolvedType, UseTree, UseTreeKind, Visitor, }, graph::{CrateId, Dependency}, hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}, @@ -27,6 +27,7 @@ use noirc_frontend::{ macros_api::{ModuleDefId, NodeInterner}, node_interner::ReferenceId, parser::{Item, ItemKind, ParsedSubModule}, + token::CustomAtrribute, ParsedModule, StructType, Type, }; use sort_text::underscore_sort_text; @@ -106,6 +107,7 @@ struct NodeFinder<'a> { nesting: usize, /// The line where an auto_import must be inserted auto_import_line: usize, + self_type: Option, } impl<'a> NodeFinder<'a> { @@ -147,6 +149,7 @@ impl<'a> NodeFinder<'a> { suggested_module_def_ids: HashSet::new(), nesting: 0, auto_import_line: 0, + self_type: None, } } @@ -191,8 +194,9 @@ impl<'a> NodeFinder<'a> { fields.remove(&field.0.contents); } + let self_prefix = false; for (field, typ) in fields { - self.completion_items.push(struct_field_completion_item(field, typ)); + self.completion_items.push(struct_field_completion_item(field, typ, self_prefix)); } } @@ -293,6 +297,7 @@ impl<'a> NodeFinder<'a> { &prefix, FunctionKind::Any, function_completion_kind, + false, // self_prefix ); return; } @@ -308,6 +313,7 @@ impl<'a> NodeFinder<'a> { &prefix, FunctionKind::Any, function_completion_kind, + false, // self_prefix ); return; } @@ -340,11 +346,21 @@ impl<'a> NodeFinder<'a> { self.local_variables_completion(&prefix); self.builtin_functions_completion(&prefix, function_completion_kind); self.builtin_values_completion(&prefix); + if let Some(self_type) = &self.self_type { + let self_prefix = true; + self.complete_type_fields_and_methods( + &self_type.clone(), + &prefix, + function_completion_kind, + self_prefix, + ); + } } RequestedItems::OnlyTypes => { self.builtin_types_completion(&prefix); self.type_parameters_completion(&prefix); } + RequestedItems::OnlyAttributeFunctions(..) => (), } self.complete_auto_imports(&prefix, requested_items, function_completion_kind); } @@ -518,16 +534,18 @@ impl<'a> NodeFinder<'a> { typ: &Type, prefix: &str, function_completion_kind: FunctionCompletionKind, + self_prefix: bool, ) { match typ { Type::Struct(struct_type, generics) => { - self.complete_struct_fields(&struct_type.borrow(), generics, prefix); + self.complete_struct_fields(&struct_type.borrow(), generics, prefix, self_prefix); } Type::MutableReference(typ) => { return self.complete_type_fields_and_methods( typ, prefix, function_completion_kind, + self_prefix, ); } Type::Alias(type_alias, _) => { @@ -536,10 +554,11 @@ impl<'a> NodeFinder<'a> { &type_alias.typ, prefix, function_completion_kind, + self_prefix, ); } Type::Tuple(types) => { - self.complete_tuple_fields(types); + self.complete_tuple_fields(types, self_prefix); } Type::FieldElement | Type::Array(_, _) @@ -565,6 +584,7 @@ impl<'a> NodeFinder<'a> { prefix, FunctionKind::SelfType(typ), function_completion_kind, + self_prefix, ); } @@ -574,6 +594,7 @@ impl<'a> NodeFinder<'a> { prefix: &str, function_kind: FunctionKind, function_completion_kind: FunctionCompletionKind, + self_prefix: bool, ) { let Some(methods_by_name) = self.interner.get_type_methods(typ) else { return; @@ -587,6 +608,8 @@ impl<'a> NodeFinder<'a> { func_id, function_completion_kind, function_kind, + None, // attribute first type + self_prefix, ) { self.completion_items.push(completion_item); self.suggested_module_def_ids.insert(ModuleDefId::FunctionId(func_id)); @@ -603,6 +626,8 @@ impl<'a> NodeFinder<'a> { function_kind: FunctionKind, function_completion_kind: FunctionCompletionKind, ) { + let self_prefix = false; + for (name, func_id) in &trait_.method_ids { if name_matches(name, prefix) { if let Some(completion_item) = self.function_completion_item( @@ -610,6 +635,8 @@ impl<'a> NodeFinder<'a> { *func_id, function_completion_kind, function_kind, + None, // attribute first type + self_prefix, ) { self.completion_items.push(completion_item); self.suggested_module_def_ids.insert(ModuleDefId::FunctionId(*func_id)); @@ -623,17 +650,19 @@ impl<'a> NodeFinder<'a> { struct_type: &StructType, generics: &[Type], prefix: &str, + self_prefix: bool, ) { for (name, typ) in &struct_type.get_fields(generics) { if name_matches(name, prefix) { - self.completion_items.push(struct_field_completion_item(name, typ)); + self.completion_items.push(struct_field_completion_item(name, typ, self_prefix)); } } } - fn complete_tuple_fields(&mut self, types: &[Type]) { + fn complete_tuple_fields(&mut self, types: &[Type], self_prefix: bool) { for (index, typ) in types.iter().enumerate() { - self.completion_items.push(field_completion_item(&index.to_string(), typ.to_string())); + let name = index.to_string(); + self.completion_items.push(field_completion_item(&name, typ.to_string(), self_prefix)); } } @@ -761,6 +790,66 @@ impl<'a> NodeFinder<'a> { None } + fn suggest_attributes(&mut self, prefix: &str, target: AttributeTarget) { + self.suggest_builtin_attributes(prefix, target); + + let function_completion_kind = FunctionCompletionKind::NameAndParameters; + let requested_items = RequestedItems::OnlyAttributeFunctions(target); + + self.complete_in_module( + self.module_id, + prefix, + PathKind::Plain, + true, + function_completion_kind, + requested_items, + ); + + self.complete_auto_imports(prefix, requested_items, function_completion_kind); + } + + fn suggest_no_arguments_attributes(&mut self, prefix: &str, attributes: &[&str]) { + for name in attributes { + if name_matches(name, prefix) { + self.completion_items.push(simple_completion_item( + *name, + CompletionItemKind::METHOD, + None, + )); + } + } + } + + fn suggest_one_argument_attributes(&mut self, prefix: &str, attributes: &[&str]) { + for name in attributes { + if name_matches(name, prefix) { + self.completion_items.push(snippet_completion_item( + format!("{}(…)", name), + CompletionItemKind::METHOD, + format!("{}(${{1:name}})", name), + None, + )); + } + } + } + + fn try_set_self_type(&mut self, pattern: &Pattern) { + match pattern { + Pattern::Identifier(ident) => { + if ident.0.contents == "self" { + let location = Location::new(ident.span(), self.file); + if let Some(ReferenceId::Local(definition_id)) = + self.interner.find_referenced(location) + { + self.self_type = Some(self.interner.definition_type(definition_id)); + } + } + } + Pattern::Mutable(pattern, ..) => self.try_set_self_type(pattern), + Pattern::Tuple(..) | Pattern::Struct(..) => (), + } + } + fn includes_span(&self, span: Span) -> bool { span.start() as usize <= self.byte_index && self.byte_index <= span.end() as usize } @@ -813,10 +902,15 @@ impl<'a> Visitor for NodeFinder<'a> { } fn visit_noir_function(&mut self, noir_function: &NoirFunction, span: Span) -> bool { + for attribute in noir_function.secondary_attributes() { + attribute.accept(AttributeTarget::Function, self); + } + let old_type_parameters = self.type_parameters.clone(); self.collect_type_parameters_in_generics(&noir_function.def.generics); for param in &noir_function.def.parameters { + self.try_set_self_type(¶m.pattern); param.typ.accept(self); } @@ -830,6 +924,7 @@ impl<'a> Visitor for NodeFinder<'a> { noir_function.def.body.accept(Some(span), self); self.type_parameters = old_type_parameters; + self.self_type = None; false } @@ -871,6 +966,10 @@ impl<'a> Visitor for NodeFinder<'a> { } fn visit_noir_struct(&mut self, noir_struct: &NoirStruct, _: Span) -> bool { + for attribute in &noir_struct.attributes { + attribute.accept(AttributeTarget::Struct, self); + } + self.type_parameters.clear(); self.collect_type_parameters_in_generics(&noir_struct.generics); @@ -945,7 +1044,13 @@ impl<'a> Visitor for NodeFinder<'a> { 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, FunctionCompletionKind::Name); + let self_prefix = false; + self.complete_type_fields_and_methods( + &typ, + prefix, + FunctionCompletionKind::Name, + self_prefix, + ); return false; } } @@ -973,7 +1078,13 @@ impl<'a> Visitor for NodeFinder<'a> { let offset = self.byte_index - method_call_expression.method_name.span().start() as usize; let prefix = prefix[0..offset].to_string(); - self.complete_type_fields_and_methods(&typ, &prefix, FunctionCompletionKind::Name); + let self_prefix = false; + self.complete_type_fields_and_methods( + &typ, + &prefix, + FunctionCompletionKind::Name, + self_prefix, + ); return false; } } @@ -1042,10 +1153,12 @@ impl<'a> Visitor for NodeFinder<'a> { { let typ = self.interner.definition_type(definition_id); let prefix = ""; + let self_prefix = false; self.complete_type_fields_and_methods( &typ, prefix, FunctionCompletionKind::NameAndParameters, + self_prefix, ); } } @@ -1072,10 +1185,12 @@ impl<'a> Visitor for NodeFinder<'a> { if let Some(typ) = self.interner.type_at_location(location) { let typ = typ.follow_bindings(); let prefix = ""; + let self_prefix = false; self.complete_type_fields_and_methods( &typ, prefix, FunctionCompletionKind::NameAndParameters, + self_prefix, ); } } @@ -1136,10 +1251,12 @@ impl<'a> Visitor for NodeFinder<'a> { if let Some(typ) = self.interner.type_at_location(location) { let typ = typ.follow_bindings(); let prefix = ident.to_string().to_case(Case::Snake); + let self_prefix = false; self.complete_type_fields_and_methods( &typ, &prefix, FunctionCompletionKind::NameAndParameters, + self_prefix, ); return false; } @@ -1201,6 +1318,14 @@ impl<'a> Visitor for NodeFinder<'a> { unresolved_types.accept(self); false } + + fn visit_custom_attribute(&mut self, attribute: &CustomAtrribute, target: AttributeTarget) { + if self.byte_index != attribute.contents_span.end() as usize { + return; + } + + self.suggest_attributes(&attribute.contents, target); + } } /// Returns true if name matches a prefix written in code. 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 54340075b15..bca1061ff47 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/builtins.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/builtins.rs @@ -1,5 +1,5 @@ use lsp_types::CompletionItemKind; -use noirc_frontend::token::Keyword; +use noirc_frontend::{ast::AttributeTarget, token::Keyword}; use strum::IntoEnumIterator; use super::{ @@ -84,6 +84,40 @@ impl<'a> NodeFinder<'a> { } } } + + pub(super) fn suggest_builtin_attributes(&mut self, prefix: &str, target: AttributeTarget) { + match target { + AttributeTarget::Module => (), + AttributeTarget::Struct => { + self.suggest_one_argument_attributes(prefix, &["abi"]); + } + AttributeTarget::Function => { + let no_arguments_attributes = &[ + "contract_library_method", + "deprecated", + "export", + "fold", + "no_predicates", + "recursive", + "test", + "varargs", + ]; + self.suggest_no_arguments_attributes(prefix, no_arguments_attributes); + + let one_argument_attributes = &["abi", "field", "foreign", "oracle"]; + self.suggest_one_argument_attributes(prefix, one_argument_attributes); + + if name_matches("test", prefix) || name_matches("should_fail_with", prefix) { + self.completion_items.push(snippet_completion_item( + "test(should_fail_with=\"...\")", + CompletionItemKind::METHOD, + "test(should_fail_with=\"${1:message}\")", + None, + )); + } + } + } + } } pub(super) fn builtin_integer_types() -> [&'static str; 8] { @@ -97,6 +131,7 @@ pub(super) fn keyword_builtin_type(keyword: &Keyword) -> Option<&'static str> { Keyword::Expr => Some("Expr"), Keyword::Field => Some("Field"), Keyword::FunctionDefinition => Some("FunctionDefinition"), + Keyword::Module => Some("Module"), Keyword::Quoted => Some("Quoted"), Keyword::StructDefinition => Some("StructDefinition"), Keyword::TraitConstraint => Some("TraitConstraint"), @@ -128,7 +163,6 @@ pub(super) fn keyword_builtin_type(keyword: &Keyword) -> Option<&'static str> { | Keyword::In | Keyword::Let | Keyword::Mod - | Keyword::Module | Keyword::Mut | Keyword::Pub | Keyword::Return diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs b/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs index 21c3a607b18..c3afc225f52 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs @@ -2,10 +2,11 @@ use lsp_types::{ Command, CompletionItem, CompletionItemKind, CompletionItemLabelDetails, InsertTextFormat, }; use noirc_frontend::{ + ast::AttributeTarget, hir_def::{function::FuncMeta, stmt::HirPattern}, macros_api::ModuleDefId, node_interner::{FuncId, GlobalId}, - Type, + QuotedType, Type, }; use super::{ @@ -33,9 +34,25 @@ impl<'a> NodeFinder<'a> { | ModuleDefId::TypeAliasId(_) | ModuleDefId::TraitId(_) => (), }, + RequestedItems::OnlyAttributeFunctions(..) => { + if !matches!(module_def_id, ModuleDefId::FunctionId(..)) { + return None; + } + } RequestedItems::AnyItems => (), } + let attribute_first_type = + if let RequestedItems::OnlyAttributeFunctions(target) = requested_items { + match target { + AttributeTarget::Module => Some(Type::Quoted(QuotedType::Module)), + AttributeTarget::Struct => Some(Type::Quoted(QuotedType::StructDefinition)), + AttributeTarget::Function => Some(Type::Quoted(QuotedType::FunctionDefinition)), + } + } else { + None + }; + match module_def_id { ModuleDefId::ModuleId(_) => Some(module_completion_item(name)), ModuleDefId::FunctionId(func_id) => self.function_completion_item( @@ -43,6 +60,8 @@ impl<'a> NodeFinder<'a> { func_id, function_completion_kind, function_kind, + attribute_first_type.as_ref(), + false, // self_prefix ), ModuleDefId::TypeId(..) => Some(self.struct_completion_item(name)), ModuleDefId::TypeAliasId(..) => Some(self.type_alias_completion_item(name)), @@ -77,6 +96,8 @@ impl<'a> NodeFinder<'a> { func_id: FuncId, function_completion_kind: FunctionCompletionKind, function_kind: FunctionKind, + attribute_first_type: Option<&Type>, + self_prefix: bool, ) -> Option { let func_meta = self.interner.function_meta(&func_id); @@ -95,6 +116,17 @@ impl<'a> NodeFinder<'a> { None }; + if let Some(attribute_first_type) = attribute_first_type { + if func_meta.parameters.is_empty() { + return None; + } + + let (_, typ, _) = &func_meta.parameters.0[0]; + if typ != attribute_first_type { + return None; + } + } + match function_kind { FunctionKind::Any => (), FunctionKind::SelfType(mut self_type) => { @@ -135,6 +167,8 @@ impl<'a> NodeFinder<'a> { } else { false }; + let name = if self_prefix { format!("self.{}", name) } else { name.clone() }; + let name = &name; let description = func_meta_type_to_string(func_meta, func_self_type.is_some()); let completion_item = match function_completion_kind { @@ -143,7 +177,13 @@ impl<'a> NodeFinder<'a> { } FunctionCompletionKind::NameAndParameters => { let kind = CompletionItemKind::FUNCTION; - let insert_text = self.compute_function_insert_text(func_meta, name, function_kind); + let skip_first_argument = attribute_first_type.is_some(); + let insert_text = self.compute_function_insert_text( + func_meta, + name, + function_kind, + skip_first_argument, + ); let label = if insert_text.ends_with("()") { format!("{}()", name) } else { @@ -179,13 +219,19 @@ impl<'a> NodeFinder<'a> { func_meta: &FuncMeta, name: &str, function_kind: FunctionKind, + skip_first_argument: bool, ) -> String { let mut text = String::new(); text.push_str(name); text.push('('); + let mut parameters = func_meta.parameters.0.iter(); + if skip_first_argument { + parameters.next(); + } + let mut index = 1; - for (pattern, _, _) in &func_meta.parameters.0 { + for (pattern, _, _) in parameters { if index == 1 { match function_kind { FunctionKind::SelfType(_) => { @@ -294,12 +340,24 @@ fn type_to_self_string(typ: &Type, string: &mut String) { } } -pub(super) fn struct_field_completion_item(field: &str, typ: &Type) -> CompletionItem { - field_completion_item(field, typ.to_string()) +pub(super) fn struct_field_completion_item( + field: &str, + typ: &Type, + self_type: bool, +) -> CompletionItem { + field_completion_item(field, typ.to_string(), self_type) } -pub(super) fn field_completion_item(field: &str, typ: impl Into) -> CompletionItem { - simple_completion_item(field, CompletionItemKind::FIELD, Some(typ.into())) +pub(super) fn field_completion_item( + field: &str, + typ: impl Into, + self_type: bool, +) -> CompletionItem { + if self_type { + simple_completion_item(format!("self.{field}"), CompletionItemKind::FIELD, Some(typ.into())) + } else { + simple_completion_item(field, CompletionItemKind::FIELD, Some(typ.into())) + } } pub(super) fn simple_completion_item( diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion/kinds.rs b/noir/noir-repo/tooling/lsp/src/requests/completion/kinds.rs index 2fe039ba331..6fa74ffdb1a 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/kinds.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/kinds.rs @@ -1,4 +1,4 @@ -use noirc_frontend::Type; +use noirc_frontend::{ast::AttributeTarget, Type}; /// 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)] @@ -27,4 +27,6 @@ pub(super) enum RequestedItems { AnyItems, // Only suggest types. OnlyTypes, + // Only attribute functions + OnlyAttributeFunctions(AttributeTarget), } diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs b/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs index a7cfa77a73d..e6a732e9142 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs @@ -7,8 +7,7 @@ mod completion_tests { completion_items::{ completion_item_with_sort_text, completion_item_with_trigger_parameter_hints_command, crate_completion_item, - field_completion_item, module_completion_item, simple_completion_item, - snippet_completion_item, + module_completion_item, simple_completion_item, snippet_completion_item, }, sort_text::{auto_import_sort_text, self_mismatch_sort_text}, }, @@ -116,6 +115,10 @@ mod completion_tests { )) } + fn field_completion_item(field: &str, typ: impl Into) -> CompletionItem { + crate::requests::completion::field_completion_item(field, typ, false) + } + #[test] async fn test_use_first_segment() { let src = r#" @@ -1888,4 +1891,65 @@ mod completion_tests { Some("(use super::barbaz)".to_string()), ); } + + #[test] + async fn test_suggests_self_fields_and_methods() { + let src = r#" + struct Foo { + foobar: Field, + } + + impl Foo { + fn foobarbaz(self) {} + + fn some_method(self) { + foob>|< + } + } + "#; + + assert_completion_excluding_auto_import( + src, + vec![ + field_completion_item("self.foobar", "Field"), + function_completion_item("self.foobarbaz()", "self.foobarbaz()", "fn(self)"), + ], + ) + .await; + } + + #[test] + async fn test_suggests_built_in_function_attribute() { + let src = r#" + #[dep>|<] + fn foo() {} + "#; + + assert_completion_excluding_auto_import( + src, + vec![simple_completion_item("deprecated", CompletionItemKind::METHOD, None)], + ) + .await; + } + + #[test] + async fn test_suggests_function_attribute() { + let src = r#" + #[some>|<] + fn foo() {} + + fn some_attr(f: FunctionDefinition, x: Field) {} + fn some_other_function(x: Field) {} + "#; + + assert_completion_excluding_auto_import( + src, + vec![function_completion_item( + "some_attr(…)", + "some_attr(${1:x})", + "fn(FunctionDefinition, Field)", + )], + ) + .await; + } } diff --git a/noir/noir-repo/tooling/nargo_cli/build.rs b/noir/noir-repo/tooling/nargo_cli/build.rs index 4dcfccdf085..7469c8be0f8 100644 --- a/noir/noir-repo/tooling/nargo_cli/build.rs +++ b/noir/noir-repo/tooling/nargo_cli/build.rs @@ -218,7 +218,7 @@ fn generate_compile_success_empty_tests(test_file: &mut File, test_data_dir: &Pa &test_dir, &format!( r#" - nargo.arg("info").arg("--arithmetic-generics").arg("--json").arg("--force"); + nargo.arg("info").arg("--json").arg("--force"); {assert_zero_opcodes}"#, ), diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json index a5593cc284c..4ec715e27eb 100644 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json +++ b/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json @@ -41,7 +41,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "portal:../../../../barretenberg/ts", + "@aztec/bb.js": "0.51.1", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh index c07d2d8a4c1..16fb26e55db 100755 --- a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh +++ b/noir/noir-repo/tooling/noirc_abi_wasm/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/yarn.lock b/noir/noir-repo/yarn.lock index f77e9f7e72e..5d1d41f58fd 100644 --- a/noir/noir-repo/yarn.lock +++ b/noir/noir-repo/yarn.lock @@ -221,18 +221,19 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": - version: 0.0.0-use.local - resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" +"@aztec/bb.js@npm:0.51.1": + version: 0.51.1 + resolution: "@aztec/bb.js@npm:0.51.1" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 tslib: ^2.4.0 bin: - bb.js: ./dest/node/main.js + bb.js: dest/node/main.js + checksum: 246953d4d2becc86001b8e6d49ab8c0b4fa4833a9bf1d2177d0fb4e271e66f9dc65e3b02b69b00fbfcb935a11e2f90b5ac229b8c8938c34604fe54b29b3accfb languageName: node - linkType: soft + linkType: hard "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -4160,7 +4161,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": "portal:../../../../barretenberg/ts" + "@aztec/bb.js": 0.51.1 "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3