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: Implement traits - first prototype #2094

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
faec260
Temp commit, code compiles
ymadzhunkov Jul 20, 2023
01f3ddd
One more step ahead
ymadzhunkov Jul 20, 2023
d7c44d8
Prep for Zahari
ymadzhunkov Jul 23, 2023
bc505a8
Fix build for Zahari
ymadzhunkov Jul 23, 2023
74a3eff
improve(traits/parsing): Implement more constructs supported by Rust
zah Jul 23, 2023
adf6807
improve(hir/trait-types): add support for generic parameters
zah Jul 23, 2023
7abbef3
Resolving of trait impl works in very simple case
ymadzhunkov Jul 24, 2023
e319984
First successful program with traits
ymadzhunkov Jul 24, 2023
2bf9ed9
Move test and remove warnings
ymadzhunkov Jul 24, 2023
cfda8e2
Add test for duplication of trait implementaion
ymadzhunkov Jul 24, 2023
fffc070
Improve the error reporting of duplicates
ymadzhunkov Jul 25, 2023
27f31a1
Add few more errors and tests
ymadzhunkov Jul 25, 2023
633d7a4
Add some initial check and test of trait implemenation
ymadzhunkov Jul 26, 2023
124d335
Fix some warnings
ymadzhunkov Jul 26, 2023
b1f3e52
Add parameter checks and reporting errors
ymadzhunkov Jul 27, 2023
4f9c9dd
Emit parser errors for trait functionalities not yet impelemented
ymadzhunkov Jul 31, 2023
98f1cc5
Forgot one space
ymadzhunkov Jul 31, 2023
7d34e14
Fix traits test nargo toml
ymadzhunkov Aug 2, 2023
6712de5
Apply cargo fmt
ymadzhunkov Aug 2, 2023
5f8fec0
Fix some clippy warnings
ymadzhunkov Aug 3, 2023
1d42384
Fix cargo clippy errors
ymadzhunkov Aug 3, 2023
a2e202b
Remove artifact from rebase
ymadzhunkov Aug 3, 2023
31355b3
Resolve some core review remarks
ymadzhunkov Aug 4, 2023
8b0510c
Rename TraitType to Trait
ymadzhunkov Aug 4, 2023
853f0e2
Fix comment & PR remarks
ymadzhunkov Aug 4, 2023
31fb5f7
Clean up commented error code"
ymadzhunkov Aug 4, 2023
36f74f9
Fix parser test and constaint keyword definition in Traits
ymadzhunkov Aug 4, 2023
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use dep::std;

trait Default {
fn default(x: Field, y: Field) -> Self;
}

struct Foo {
bar: Field,
array: [Field; 2],
}

impl Default for Foo {
fn default(x: Field,y: Field) -> Self {
Self { bar: x, array: [x,y] }
}
}

// Duplicate trait declarations should not compile
trait Default {
fn default(x: Field) -> Self;
}

fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use dep::std;

trait Default {
fn default(x: Field, y: Field) -> Self;
}

struct Foo {
bar: Field,
array: [Field; 2],
}

// Duplicate trait implementations should not compile
impl Default for Foo {
fn default(x: Field,y: Field) -> Self {
Self { bar: x, array: [x,y] }
}
}

// Duplicate trait implementations should not compile
impl Default for Foo {
fn default(x: Field, y: Field) -> Self {
Self { bar: y, array: [y,x] }
}
}


fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use dep::std;

struct Foo {
bar: Field,
array: [Field; 2],
}

struct Default {
x: Field,
z: Field,
}

// Default is struct not a trait
impl Default for Foo {
fn default(x: Field, y: Field) -> Self {
Self { bar: x, array: [x,y] }
}
}

fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use dep::std;

trait Default {
fn default(x: Field, y: Field) -> Self;
}

struct Foo {
bar: Field,
array: [Field; 2],
}

impl Default for Foo {
fn default(x: Field) -> Self {
Self { bar: x, array: [x, x] }
}
}

fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
18 changes: 18 additions & 0 deletions crates/nargo_cli/tests/compile_tests_data/fail/trait_not_exists.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use dep::std;

struct Foo {
bar: Field,
array: [Field; 2],
}

// Default trait does not exist
impl Default for Foo {
fn default(x: Field, y: Field) -> Self {
Self { bar: x, array: [x,y] }
}
}

fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use dep::std;

trait Default {
fn default(x: Field, y: Field) -> Self;
}

struct Foo {
bar: Field,
array: [Field; 2],
}

// wrong trait name method should not compile
impl Default for Foo {
fn default_wrong_name(x: Field, y: Field) -> Self {
Self { bar: x, array: [x,y] }
}
}

fn main(x: Field, y: Field) {
let first = Foo::default_wrong_name(x,y);
assert(first.bar == x);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use dep::std;

trait Default {
fn default(x: Field, y: Field) -> Self;
}

struct Foo {
bar: Field,
array: [Field; 2],
}

impl Default for Foo {
fn default(x: Field, y: Field) -> Field {
x
}
}

fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use dep::std;

trait Default {
fn default(x: Field, y: Field) -> Self;
}

struct Foo {
bar: Field,
array: [Field; 2],
}

impl Default for Foo {
fn default(x: Field, y: Foo) -> Self {
Self { bar: x, array: [x, y.bar] }
}
}

fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use dep::std;

trait Default {
fn default(x: Field, y: Field) -> Self;
}

struct Foo {
bar: Field,
array: [Field; 2],
}

impl Default for Foo {
fn default(x: Field) -> Self {
Self { bar: x, array: [x, x] }
}
}

fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
6 changes: 6 additions & 0 deletions crates/nargo_cli/tests/test_data/traits/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "traits"
authors = [""]
compiler_version = "0.1"

[dependencies]
2 changes: 2 additions & 0 deletions crates/nargo_cli/tests/test_data/traits/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x = "5"
y = "1"
21 changes: 21 additions & 0 deletions crates/nargo_cli/tests/test_data/traits/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use dep::std;

trait Default {
fn default(x: Field, y: Field) -> Self;
}

struct Foo {
bar: Field,
array: [Field; 2],
}

impl Default for Foo {
fn default(x: Field,y: Field) -> Self {
Self { bar: x, array: [x,y] }
}
}

fn main(x: Field, y: Field) {
let first = Foo::default(x,y);
assert(first.bar == x);
}
1 change: 1 addition & 0 deletions crates/nargo_cli/tests/test_data/traits/target/main.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"field"},"visibility":"private"},{"name":"y","type":{"kind":"field"},"visibility":"private"}],"param_witnesses":{"x":[1],"y":[2]},"return_type":null,"return_witnesses":[]},"bytecode":[155,194,60,97,194,4,0],"proving_key":null,"verification_key":null}
39 changes: 34 additions & 5 deletions crates/noirc_frontend/src/ast/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ use std::fmt::Display;
use iter_extended::vecmap;
use noirc_errors::Span;

use crate::{Ident, NoirFunction, UnresolvedGenerics, UnresolvedType};
use crate::{BlockExpression, Expression, Ident, NoirFunction, UnresolvedGenerics, UnresolvedType};

/// AST node for trait definitions:
/// `trait name<generics> { ... items ... }`
#[derive(Clone, Debug)]
pub struct NoirTrait {
pub name: Ident,
pub generics: Vec<Ident>,
pub where_clause: Vec<TraitConstraint>,
pub span: Span,
pub items: Vec<TraitItem>,
}

Expand All @@ -24,6 +26,12 @@ pub enum TraitItem {
parameters: Vec<(Ident, UnresolvedType)>,
return_type: UnresolvedType,
where_clause: Vec<TraitConstraint>,
body: Option<BlockExpression>,
},
Constant {
name: Ident,
typ: UnresolvedType,
default_value: Option<Expression>,
},
Type {
name: Ident,
Expand Down Expand Up @@ -68,6 +76,7 @@ pub struct TraitConstraint {
#[derive(Clone, Debug)]
pub enum TraitImplItem {
Function(NoirFunction),
Constant(Ident, UnresolvedType, Expression),
Type { name: Ident, alias: UnresolvedType },
}

Expand Down Expand Up @@ -110,7 +119,7 @@ impl Display for NoirTrait {
impl Display for TraitItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TraitItem::Function { name, generics, parameters, return_type, where_clause } => {
TraitItem::Function { name, generics, parameters, return_type, where_clause, body } => {
let generics = vecmap(generics, |generic| generic.to_string());
let parameters = vecmap(parameters, |(name, typ)| format!("{name}: {typ}"));
let where_clause = vecmap(where_clause, ToString::to_string);
Expand All @@ -121,9 +130,25 @@ impl Display for TraitItem {

write!(
f,
"fn {name}<{}>({}) -> {} where {};",
"fn {name}<{}>({}) -> {} where {}",
generics, parameters, return_type, where_clause
)
)?;

if let Some(body) = body {
write!(f, "{}", body)
} else {
write!(f, ";")
}
}
TraitItem::Constant { name, typ, default_value } => {
// TODO: Shall we use `comptime` or `const` here?
write!(f, "comptime {}: {}", name, typ)?;

if let Some(default_value) = default_value {
write!(f, "{};", default_value)
} else {
write!(f, ";")
}
}
TraitItem::Type { name } => write!(f, "type {name};"),
}
Expand Down Expand Up @@ -159,7 +184,11 @@ impl Display for TraitImplItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TraitImplItem::Function(function) => function.fmt(f),
TraitImplItem::Type { name, alias } => write!(f, "type {name} = {alias}"),
TraitImplItem::Type { name, alias } => write!(f, "type {name} = {alias};"),
// TODO: Should we use `comptime` or `const` here?
TraitImplItem::Constant(name, typ, value) => {
write!(f, "comptime {}: {} = {};", name, typ, value)
}
}
}
}
Loading