From 63a227f5bcae4aa89a51769880ee75bdb7dee3f7 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 19:16:07 +0000 Subject: [PATCH 1/9] where clause on impl --- aztec_macros/src/transforms/events.rs | 1 + aztec_macros/src/transforms/note_interface.rs | 1 + aztec_macros/src/transforms/storage.rs | 2 ++ compiler/noirc_frontend/src/ast/traits.rs | 1 + .../src/hir/def_collector/dc_mod.rs | 6 +++- compiler/noirc_frontend/src/parser/parser.rs | 14 ++++++-- .../impl_where_clause/Nargo.toml | 7 ++++ .../impl_where_clause/src/main.nr | 34 +++++++++++++++++++ .../Nargo.toml | 2 +- .../src/main.nr | 0 10 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 test_programs/compile_success_empty/impl_where_clause/Nargo.toml create mode 100644 test_programs/compile_success_empty/impl_where_clause/src/main.nr rename test_programs/compile_success_empty/{impl_with_where_clause => trait_impl_with_where_clause}/Nargo.toml (58%) rename test_programs/compile_success_empty/{impl_with_where_clause => trait_impl_with_where_clause}/src/main.nr (100%) diff --git a/aztec_macros/src/transforms/events.rs b/aztec_macros/src/transforms/events.rs index 69cb6ddafc3..74a7be8eb95 100644 --- a/aztec_macros/src/transforms/events.rs +++ b/aztec_macros/src/transforms/events.rs @@ -83,6 +83,7 @@ pub fn generate_selector_impl(structure: &mut NoirStruct) -> TypeImpl { type_span: structure.span, generics: vec![], methods: vec![(NoirFunction::normal(selector_fn_def), Span::default())], + where_clause: vec![], } } diff --git a/aztec_macros/src/transforms/note_interface.rs b/aztec_macros/src/transforms/note_interface.rs index f0e7d0d5034..80417c14322 100644 --- a/aztec_macros/src/transforms/note_interface.rs +++ b/aztec_macros/src/transforms/note_interface.rs @@ -69,6 +69,7 @@ pub fn generate_note_interface_impl(module: &mut SortedModule) -> Result<(), Azt type_span: note_struct.name.span(), generics: vec![], methods: vec![], + where_clause: vec![], }; module.impls.push(default_impl.clone()); module.impls.last_mut().unwrap() diff --git a/aztec_macros/src/transforms/storage.rs b/aztec_macros/src/transforms/storage.rs index 8b778b4cca6..872e7c37801 100644 --- a/aztec_macros/src/transforms/storage.rs +++ b/aztec_macros/src/transforms/storage.rs @@ -246,6 +246,8 @@ pub fn generate_storage_implementation( generics: vec![generic_context_ident], methods: vec![(init, Span::default())], + + where_clause: vec![], }; module.impls.push(storage_impl); diff --git a/compiler/noirc_frontend/src/ast/traits.rs b/compiler/noirc_frontend/src/ast/traits.rs index 772675723b5..9d7345d0270 100644 --- a/compiler/noirc_frontend/src/ast/traits.rs +++ b/compiler/noirc_frontend/src/ast/traits.rs @@ -49,6 +49,7 @@ pub struct TypeImpl { pub object_type: UnresolvedType, pub type_span: Span, pub generics: UnresolvedGenerics, + pub where_clause: Vec, pub methods: Vec<(NoirFunction, Span)>, } diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 5c196324b7d..df6401d3022 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -141,7 +141,7 @@ impl<'a> ModCollector<'a> { fn collect_impls(&mut self, context: &mut Context, impls: Vec, krate: CrateId) { let module_id = ModuleId { krate, local_id: self.module_id }; - for r#impl in impls { + for mut r#impl in impls { let mut unresolved_functions = UnresolvedFunctions { file_id: self.file_id, functions: Vec::new(), @@ -149,6 +149,10 @@ impl<'a> ModCollector<'a> { self_type: None, }; + for (method, _) in &mut r#impl.methods { + method.def.where_clause.append(&mut r#impl.where_clause); + } + for (method, _) in r#impl.methods { let func_id = context.def_interner.push_empty_fn(); let location = Location::new(method.span(), self.file_id); diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index e8838c58772..1b958764694 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -225,11 +225,21 @@ fn implementation() -> impl NoirParser { keyword(Keyword::Impl) .ignore_then(function::generics()) .then(parse_type().map_with_span(|typ, span| (typ, span))) + .then(where_clause()) .then_ignore(just(Token::LeftBrace)) .then(spanned(function::function_definition(true)).repeated()) .then_ignore(just(Token::RightBrace)) - .map(|((generics, (object_type, type_span)), methods)| { - TopLevelStatement::Impl(TypeImpl { generics, object_type, type_span, methods }) + // .map(|((generics, (object_type, type_span)), methods)| { + .map(|args| { + let ((other_args, where_clause), methods) = args; + let (generics, (object_type, type_span)) = other_args; + TopLevelStatement::Impl(TypeImpl { + generics, + object_type, + type_span, + where_clause, + methods, + }) }) } diff --git a/test_programs/compile_success_empty/impl_where_clause/Nargo.toml b/test_programs/compile_success_empty/impl_where_clause/Nargo.toml new file mode 100644 index 00000000000..7d0d5f3513e --- /dev/null +++ b/test_programs/compile_success_empty/impl_where_clause/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "impl_where_clause" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_success_empty/impl_where_clause/src/main.nr b/test_programs/compile_success_empty/impl_where_clause/src/main.nr new file mode 100644 index 00000000000..0fbda1db39b --- /dev/null +++ b/test_programs/compile_success_empty/impl_where_clause/src/main.nr @@ -0,0 +1,34 @@ +struct MyStruct { + a: u32, + b: T, +} + +struct InnerStruct { + a: Field, + b: Field, +} + +trait MyEq { + fn my_eq(self, other: Self) -> bool; +} + +impl MyEq for InnerStruct { + fn my_eq(self, other: InnerStruct) -> bool { + (self.a == other.a) & (self.b == other.b) + } +} + +impl MyStruct where T: MyEq { + fn my_eq(self, other: Self) -> bool { + (self.a == other.a) & self.b.my_eq(other.b) + } +} + +fn main() { + let inner = InnerStruct { a: 1, b: 2 }; + let my_struct = MyStruct { a: 5, b: inner }; + assert(my_struct.my_eq(my_struct)); + + let mut my_struct_new = MyStruct { a: 5, b: InnerStruct { a: 10, b: 15 } }; + assert(my_struct_new.my_eq(my_struct_new)); +} \ No newline at end of file diff --git a/test_programs/compile_success_empty/impl_with_where_clause/Nargo.toml b/test_programs/compile_success_empty/trait_impl_with_where_clause/Nargo.toml similarity index 58% rename from test_programs/compile_success_empty/impl_with_where_clause/Nargo.toml rename to test_programs/compile_success_empty/trait_impl_with_where_clause/Nargo.toml index ef9bdce2640..672569634ea 100644 --- a/test_programs/compile_success_empty/impl_with_where_clause/Nargo.toml +++ b/test_programs/compile_success_empty/trait_impl_with_where_clause/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "impl_with_where_clause" +name = "trait_impl_with_where_clause" type = "bin" authors = [""] diff --git a/test_programs/compile_success_empty/impl_with_where_clause/src/main.nr b/test_programs/compile_success_empty/trait_impl_with_where_clause/src/main.nr similarity index 100% rename from test_programs/compile_success_empty/impl_with_where_clause/src/main.nr rename to test_programs/compile_success_empty/trait_impl_with_where_clause/src/main.nr From d835d676955fd71c7c554cb893c42f389ab44105 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 19:31:08 +0000 Subject: [PATCH 2/9] add small docs info on impl where --- docs/docs/noir/concepts/traits.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/docs/noir/concepts/traits.md b/docs/docs/noir/concepts/traits.md index df7cb9ebda0..5d21b744819 100644 --- a/docs/docs/noir/concepts/traits.md +++ b/docs/docs/noir/concepts/traits.md @@ -145,9 +145,15 @@ fn main() { } ``` +### Generic Implementations With Where Clauses + +Where clauses can be placed on struct implementations themselves to restrict generics. + +For example, while `impl Foo` + ### Generic Trait Implementations With Where Clauses -Where clauses can also be placed on trait implementations themselves to restrict generics in a similar way. +Where clauses can be placed on trait implementations themselves to restrict generics in a similar way. For example, while `impl Foo for T` implements the trait `Foo` for every type, `impl Foo for T where T: Bar` will implement `Foo` only for types that also implement `Bar`. This is often used for implementing generic types. For example, here is the implementation for array equality: @@ -169,6 +175,22 @@ impl Eq for [T; N] where T: Eq { } ``` +Where clauses can also be placed on struct implementations. +For example, here is a method utilizing a generic type that implements the equality trait. + +```rust +struct Foo { + a: u32, + b: T, +} + +impl Foo where T: Eq { + fn eq(self, other: Self) -> bool { + (self.a == other.a) & self.b.eq(other.b) + } +} +``` + ## Generic Traits Traits themselves can also be generic by placing the generic arguments after the trait name. These generics are in From e733bae39bdc408f3f4f4f5ff72f8f421813bbeb Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 19:31:32 +0000 Subject: [PATCH 3/9] remove old comment --- compiler/noirc_frontend/src/parser/parser.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index 1b958764694..56caea38756 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -229,7 +229,6 @@ fn implementation() -> impl NoirParser { .then_ignore(just(Token::LeftBrace)) .then(spanned(function::function_definition(true)).repeated()) .then_ignore(just(Token::RightBrace)) - // .map(|((generics, (object_type, type_span)), methods)| { .map(|args| { let ((other_args, where_clause), methods) = args; let (generics, (object_type, type_span)) = other_args; From c326d4ce88f7d49345c43254f633910d7d9a2658 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 19:55:17 +0000 Subject: [PATCH 4/9] add impl with where clause to fmt tests --- tooling/nargo_fmt/src/visitor/item.rs | 4 ++-- tooling/nargo_fmt/tests/expected/impl.nr | 6 ++++++ tooling/nargo_fmt/tests/input/impl.nr | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tooling/nargo_fmt/src/visitor/item.rs b/tooling/nargo_fmt/src/visitor/item.rs index 3cfee4f46ad..5aaaf20ff47 100644 --- a/tooling/nargo_fmt/src/visitor/item.rs +++ b/tooling/nargo_fmt/src/visitor/item.rs @@ -188,8 +188,8 @@ impl super::FmtVisitor<'_> { continue; } - let slice = - self.slice(self.last_position..impl_.object_type.span.unwrap().end()); + let before_brace = self.span_before(span, Token::LeftBrace).start(); + let slice = self.slice(self.last_position..before_brace).trim(); let after_brace = self.span_after(span, Token::LeftBrace).start(); self.last_position = after_brace; diff --git a/tooling/nargo_fmt/tests/expected/impl.nr b/tooling/nargo_fmt/tests/expected/impl.nr index ec734b57970..3c2fa42837a 100644 --- a/tooling/nargo_fmt/tests/expected/impl.nr +++ b/tooling/nargo_fmt/tests/expected/impl.nr @@ -19,3 +19,9 @@ impl MyType { impl MyType { fn method(self) {} } + +impl MyStruct where T: MyEq { + fn my_eq(self, other: Self) -> bool { + (self.a == other.a) & self.b.my_eq(other.b) + } +} diff --git a/tooling/nargo_fmt/tests/input/impl.nr b/tooling/nargo_fmt/tests/input/impl.nr index ea909dfad44..4ca838c2964 100644 --- a/tooling/nargo_fmt/tests/input/impl.nr +++ b/tooling/nargo_fmt/tests/input/impl.nr @@ -19,3 +19,9 @@ fn method(self) {} impl MyType { fn method(self) {} } + +impl MyStruct where T: MyEq { + fn my_eq(self, other: Self) -> bool { + (self.a == other.a) & self.b.my_eq(other.b) + } +} \ No newline at end of file From 4f3fe0cf7a8ea2a50e89d96ae2d0f400c3119820 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 20:06:31 +0000 Subject: [PATCH 5/9] fmt --- .../compile_success_empty/impl_where_clause/src/main.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_programs/compile_success_empty/impl_where_clause/src/main.nr b/test_programs/compile_success_empty/impl_where_clause/src/main.nr index 0fbda1db39b..2f3223efaae 100644 --- a/test_programs/compile_success_empty/impl_where_clause/src/main.nr +++ b/test_programs/compile_success_empty/impl_where_clause/src/main.nr @@ -31,4 +31,4 @@ fn main() { let mut my_struct_new = MyStruct { a: 5, b: InnerStruct { a: 10, b: 15 } }; assert(my_struct_new.my_eq(my_struct_new)); -} \ No newline at end of file +} From 51a82dfe091dcff73334f50e1a89fd375e7c4c55 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 16:48:51 -0400 Subject: [PATCH 6/9] Update compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs Co-authored-by: jfecher --- compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index df6401d3022..00e0a0f5e91 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -150,7 +150,7 @@ impl<'a> ModCollector<'a> { }; for (method, _) in &mut r#impl.methods { - method.def.where_clause.append(&mut r#impl.where_clause); + method.def.where_clause.extend(r#impl.where_clause.clone()); } for (method, _) in r#impl.methods { From 1c650ce66159eb52b7a23876c4301b35f8cdc550 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 16:48:55 -0400 Subject: [PATCH 7/9] Update compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs Co-authored-by: jfecher --- compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 00e0a0f5e91..38b0b82e911 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -141,7 +141,7 @@ impl<'a> ModCollector<'a> { fn collect_impls(&mut self, context: &mut Context, impls: Vec, krate: CrateId) { let module_id = ModuleId { krate, local_id: self.module_id }; - for mut r#impl in impls { + for r#impl in impls { let mut unresolved_functions = UnresolvedFunctions { file_id: self.file_id, functions: Vec::new(), From d4da84c9cc9ab12476f8f8ae3cabf049429ca56d Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 16:49:31 -0400 Subject: [PATCH 8/9] Update docs/docs/noir/concepts/traits.md --- docs/docs/noir/concepts/traits.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/docs/noir/concepts/traits.md b/docs/docs/noir/concepts/traits.md index 5d21b744819..51305b38c16 100644 --- a/docs/docs/noir/concepts/traits.md +++ b/docs/docs/noir/concepts/traits.md @@ -145,12 +145,6 @@ fn main() { } ``` -### Generic Implementations With Where Clauses - -Where clauses can be placed on struct implementations themselves to restrict generics. - -For example, while `impl Foo` - ### Generic Trait Implementations With Where Clauses Where clauses can be placed on trait implementations themselves to restrict generics in a similar way. From aa23e1575e01048cf08b70ebabab006be611ecba Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 24 Jun 2024 20:53:58 +0000 Subject: [PATCH 9/9] fixup after suggested changes --- compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 38b0b82e911..e7bbe5951d8 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -149,12 +149,9 @@ impl<'a> ModCollector<'a> { self_type: None, }; - for (method, _) in &mut r#impl.methods { - method.def.where_clause.extend(r#impl.where_clause.clone()); - } - - for (method, _) in r#impl.methods { + for (mut method, _) in r#impl.methods { let func_id = context.def_interner.push_empty_fn(); + method.def.where_clause.extend(r#impl.where_clause.clone()); let location = Location::new(method.span(), self.file_id); context.def_interner.push_function(func_id, &method.def, module_id, location); unresolved_functions.push_fn(self.module_id, func_id, method);