Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions aztec_macros/src/transforms/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![],
}
}

Expand Down
1 change: 1 addition & 0 deletions aztec_macros/src/transforms/note_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 2 additions & 0 deletions aztec_macros/src/transforms/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/ast/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub struct TypeImpl {
pub object_type: UnresolvedType,
pub type_span: Span,
pub generics: UnresolvedGenerics,
pub where_clause: Vec<UnresolvedTraitConstraint>,
pub methods: Vec<(NoirFunction, Span)>,
}

Expand Down
4 changes: 4 additions & 0 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ 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 {
let func_id = context.def_interner.push_empty_fn();
let location = Location::new(method.span(), self.file_id);
Expand Down
13 changes: 11 additions & 2 deletions compiler/noirc_frontend/src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,20 @@ fn implementation() -> impl NoirParser<TopLevelStatement> {
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(|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,
})
})
}

Expand Down
24 changes: 23 additions & 1 deletion docs/docs/noir/concepts/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> 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<T> Foo for T` implements the trait `Foo` for every type, `impl<T> 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:
Expand All @@ -169,6 +175,22 @@ impl<T, N> 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<T> {
a: u32,
b: T,
}

impl<T> Foo<T> 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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "impl_where_clause"
type = "bin"
authors = [""]
compiler_version = ">=0.31.0"

[dependencies]
34 changes: 34 additions & 0 deletions test_programs/compile_success_empty/impl_where_clause/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
struct MyStruct<T> {
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<T> MyStruct<T> 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));
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "impl_with_where_clause"
name = "trait_impl_with_where_clause"
type = "bin"
authors = [""]

Expand Down
4 changes: 2 additions & 2 deletions tooling/nargo_fmt/src/visitor/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
6 changes: 6 additions & 0 deletions tooling/nargo_fmt/tests/expected/impl.nr
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@ impl MyType {
impl MyType {
fn method(self) {}
}

impl<T> MyStruct<T> where T: MyEq {
fn my_eq(self, other: Self) -> bool {
(self.a == other.a) & self.b.my_eq(other.b)
}
}
6 changes: 6 additions & 0 deletions tooling/nargo_fmt/tests/input/impl.nr
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@ fn method(self) {}
impl MyType {
fn method(self) {}
}

impl<T> MyStruct<T> where T: MyEq {
fn my_eq(self, other: Self) -> bool {
(self.a == other.a) & self.b.my_eq(other.b)
}
}