Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(frontend): Where clause on impl #5320

Merged
merged 10 commits into from
Jun 24, 2024
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 @@
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 Expand Up @@ -387,7 +388,7 @@

// Generate the deserialize_content method as
//
// fn deserialize_content(serialized_note: [Field; NOTE_SERILIZED_LEN]) -> Self {

Check warning on line 391 in aztec_macros/src/transforms/note_interface.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (SERILIZED)
// NoteType {
// note_field1: serialized_note[0] as Field,
// note_field2: NoteFieldType2::from_field(serialized_note[1])...
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 @@ -173,7 +173,7 @@
///
/// To:
///
/// impl<Context> Storage<Contex> {

Check warning on line 176 in aztec_macros/src/transforms/storage.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Contex)
/// fn init(context: Context) -> Self {
/// Storage {
/// a_map: Map::new(context, 0, |context, slot| {
Expand Down Expand Up @@ -246,6 +246,8 @@
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`
jfecher marked this conversation as resolved.
Show resolved Hide resolved

vezenovm marked this conversation as resolved.
Show resolved Hide resolved
### 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)
}
}
Loading