Skip to content

Commit

Permalink
feat: trait aliases (noir-lang/noir#6431)
Browse files Browse the repository at this point in the history
chore: Added test showcasing performance regression (noir-lang/noir#6566)
chore: embed package name in logs (noir-lang/noir#6564)
chore: remove separate acvm versioning (noir-lang/noir#6561)
chore: switch to 1.0.0-beta versioning (noir-lang/noir#6503)
chore: Release Noir(0.39.0) (noir-lang/noir#6484)
feat: Sync from aztec-packages (noir-lang/noir#6557)
feat(ssa): Unroll small loops in brillig (noir-lang/noir#6505)
fix: Do a shallow follow_bindings before unification (noir-lang/noir#6558)
chore: remove some `_else_condition` tech debt (noir-lang/noir#6522)
chore: revert #6375 (noir-lang/noir#6552)
feat: simplify constant MSM calls in SSA (noir-lang/noir#6547)
chore(test): Remove duplicate brillig tests (noir-lang/noir#6523)
chore: restructure `noirc_evaluator` crate (noir-lang/noir#6534)
fix: take blackbox function outputs into account when merging expressions (noir-lang/noir#6532)
chore: Add `Instruction::MakeArray` to SSA (noir-lang/noir#6071)
feat(profiler): Reduce memory in Brillig execution flamegraph (noir-lang/noir#6538)
chore: convert some tests to use SSA parser (noir-lang/noir#6543)
chore(ci): bump mac github runner image to `macos-14` (noir-lang/noir#6545)
chore(test): More descriptive labels in test matrix (noir-lang/noir#6542)
chore: Remove unused methods from implicit numeric generics (noir-lang/noir#6541)
fix: Fix poor handling of aliased references in flattening pass causing some values to be zeroed (noir-lang/noir#6434)
fix: allow range checks to be performed within the comptime intepreter (noir-lang/noir#6514)
fix: disallow `#[test]` on associated functions (noir-lang/noir#6449)
chore(ssa): Skip array_set pass for Brillig functions (noir-lang/noir#6513)
chore: Reverse ssa parser diff order (noir-lang/noir#6511)
chore: Parse negatives in SSA parser (noir-lang/noir#6510)
feat: avoid unnecessary ssa passes while loop unrolling (noir-lang/noir#6509)
fix(tests): Use a file lock as well as a mutex to isolate tests cases (noir-lang/noir#6508)
fix: set local_module before elaborating each trait (noir-lang/noir#6506)
fix: parse Slice type in SSa (noir-lang/noir#6507)
fix: perform arithmetic simplification through `CheckedCast` (noir-lang/noir#6502)
feat: SSA parser (noir-lang/noir#6489)
chore(test): Run test matrix on test_programs (noir-lang/noir#6429)
chore(ci): fix cargo deny (noir-lang/noir#6501)
feat: Deduplicate instructions across blocks (noir-lang/noir#6499)
chore: move tests for arithmetic generics closer to the code (noir-lang/noir#6497)
fix(docs): Fix broken links in oracles doc (noir-lang/noir#6488)
fix: Treat all parameters as possible aliases of each other (noir-lang/noir#6477)
chore: bump rust dependencies (noir-lang/noir#6482)
feat: use a full `BlackBoxFunctionSolver` implementation when execution brillig during acirgen (noir-lang/noir#6481)
chore(docs): Update How to Oracles (noir-lang/noir#5675)
chore: Release Noir(0.38.0) (noir-lang/noir#6422)
fix(ssa): Change array_set to not mutate slices coming from function inputs (noir-lang/noir#6463)
chore: update example to show how to split public inputs in bash (noir-lang/noir#6472)
fix: Discard optimisation that would change execution ordering or that is related to call outputs (noir-lang/noir#6461)
chore: proptest for `canonicalize` on infix type expressions (noir-lang/noir#6269)
fix: let formatter respect newlines between comments (noir-lang/noir#6458)
fix: check infix expression is valid in program input (noir-lang/noir#6450)
fix: don't crash on AsTraitPath with empty path (noir-lang/noir#6454)
fix(tests): Prevent EOF error while running test programs (noir-lang/noir#6455)
fix(sea): mem2reg to treat block input references as alias (noir-lang/noir#6452)
chore: revamp attributes (noir-lang/noir#6424)
feat!: Always Check Arithmetic Generics at Monomorphization (noir-lang/noir#6329)
chore: split path and import lookups (noir-lang/noir#6430)
fix(ssa): Resolve value IDs in terminator before comparing to array (noir-lang/noir#6448)
fix: right shift is not a regular division (noir-lang/noir#6400)
  • Loading branch information
AztecBot committed Nov 21, 2024
2 parents 57b4735 + ba1d3a3 commit 1ca25e0
Show file tree
Hide file tree
Showing 19 changed files with 1,242 additions and 110 deletions.
2 changes: 1 addition & 1 deletion .noir-sync-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
29d46fd36aaf0da7041973f3c0e49096bd978adc
68c32b4ffd9b069fe4b119327dbf4018c17ab9d4
281 changes: 228 additions & 53 deletions noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions noir/noir-repo/compiler/noirc_frontend/src/ast/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct NoirTrait {
pub items: Vec<Documented<TraitItem>>,
pub attributes: Vec<SecondaryAttribute>,
pub visibility: ItemVisibility,
pub is_alias: bool,
}

/// Any declaration inside the body of a trait that a user is required to
Expand Down Expand Up @@ -77,6 +78,9 @@ pub struct NoirTraitImpl {
pub where_clause: Vec<UnresolvedTraitConstraint>,

pub items: Vec<Documented<TraitImplItem>>,

/// true if generated at compile-time, e.g. from a trait alias
pub is_synthetic: bool,
}

/// Represents a simple trait constraint such as `where Foo: TraitY<U, V>`
Expand Down Expand Up @@ -130,12 +134,19 @@ impl Display for TypeImpl {
}
}

// TODO: display where clauses (follow-up issue)
impl Display for NoirTrait {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let generics = vecmap(&self.generics, |generic| generic.to_string());
let generics = if generics.is_empty() { "".into() } else { generics.join(", ") };

write!(f, "trait {}{}", self.name, generics)?;

if self.is_alias {
let bounds = vecmap(&self.bounds, |bound| bound.to_string()).join(" + ");
return write!(f, " = {};", bounds);
}

if !self.bounds.is_empty() {
let bounds = vecmap(&self.bounds, |bound| bound.to_string()).join(" + ");
write!(f, ": {}", bounds)?;
Expand Down Expand Up @@ -222,6 +233,11 @@ impl Display for TraitBound {

impl Display for NoirTraitImpl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Synthetic NoirTraitImpl's don't get printed
if self.is_synthetic {
return Ok(());
}

write!(f, "impl")?;
if !self.impl_generics.is_empty() {
write!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ pub enum TypeCheckError {

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NoMatchingImplFoundError {
constraints: Vec<(Type, String)>,
pub(crate) constraints: Vec<(Type, String)>,
pub span: Span,
}

Expand Down
2 changes: 2 additions & 0 deletions noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub enum ParserErrorReason {
AssociatedTypesNotAllowedInPaths,
#[error("Associated types are not allowed on a method call")]
AssociatedTypesNotAllowedInMethodCalls,
#[error("Empty trait alias")]
EmptyTraitAlias,
#[error(
"Wrong number of arguments for attribute `{}`. Expected {}, found {}",
name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ impl<'a> Parser<'a> {
let object_type = self.parse_type_or_error();
let where_clause = self.parse_where_clause();
let items = self.parse_trait_impl_body();
let is_synthetic = false;

NoirTraitImpl {
impl_generics,
Expand All @@ -121,6 +122,7 @@ impl<'a> Parser<'a> {
object_type,
where_clause,
items,
is_synthetic,
}
}

Expand Down
72 changes: 41 additions & 31 deletions noir/noir-repo/compiler/noirc_frontend/src/parser/parser/item.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use iter_extended::vecmap;

use crate::{
parser::{labels::ParsingRuleLabel, Item, ItemKind},
token::{Keyword, Token},
Expand All @@ -13,31 +15,32 @@ impl<'a> Parser<'a> {
}

pub(crate) fn parse_module_items(&mut self, nested: bool) -> Vec<Item> {
self.parse_many("items", without_separator(), |parser| {
self.parse_many_to_many("items", without_separator(), |parser| {
parser.parse_module_item_in_list(nested)
})
}

fn parse_module_item_in_list(&mut self, nested: bool) -> Option<Item> {
fn parse_module_item_in_list(&mut self, nested: bool) -> Vec<Item> {
loop {
// We only break out of the loop on `}` if we are inside a `mod { ..`
if nested && self.at(Token::RightBrace) {
return None;
return vec![];
}

// We always break on EOF (we don't error because if we are inside `mod { ..`
// the outer parsing logic will error instead)
if self.at_eof() {
return None;
return vec![];
}

let Some(item) = self.parse_item() else {
let parsed_items = self.parse_item();
if parsed_items.is_empty() {
// If we couldn't parse an item we check which token we got
match self.token.token() {
Token::RightBrace if nested => {
return None;
return vec![];
}
Token::EOF => return None,
Token::EOF => return vec![],
_ => (),
}

Expand All @@ -47,7 +50,7 @@ impl<'a> Parser<'a> {
continue;
};

return Some(item);
return parsed_items;
}
}

Expand Down Expand Up @@ -85,15 +88,19 @@ impl<'a> Parser<'a> {
}

/// Item = OuterDocComments ItemKind
fn parse_item(&mut self) -> Option<Item> {
fn parse_item(&mut self) -> Vec<Item> {
let start_span = self.current_token_span;
let doc_comments = self.parse_outer_doc_comments();
let kind = self.parse_item_kind()?;
let kinds = self.parse_item_kind();
let span = self.span_since(start_span);

Some(Item { kind, span, doc_comments })
vecmap(kinds, |kind| Item { kind, span, doc_comments: doc_comments.clone() })
}

/// This method returns one 'ItemKind' in the majority of cases.
/// The current exception is when parsing a trait alias,
/// which returns both the trait and the impl.
///
/// ItemKind
/// = InnerAttribute
/// | Attributes Modifiers
Expand All @@ -106,9 +113,9 @@ impl<'a> Parser<'a> {
/// | TypeAlias
/// | Function
/// )
fn parse_item_kind(&mut self) -> Option<ItemKind> {
fn parse_item_kind(&mut self) -> Vec<ItemKind> {
if let Some(kind) = self.parse_inner_attribute() {
return Some(ItemKind::InnerAttribute(kind));
return vec![ItemKind::InnerAttribute(kind)];
}

let start_span = self.current_token_span;
Expand All @@ -122,78 +129,81 @@ impl<'a> Parser<'a> {
self.comptime_mutable_and_unconstrained_not_applicable(modifiers);

let use_tree = self.parse_use_tree();
return Some(ItemKind::Import(use_tree, modifiers.visibility));
return vec![ItemKind::Import(use_tree, modifiers.visibility)];
}

if let Some(is_contract) = self.eat_mod_or_contract() {
self.comptime_mutable_and_unconstrained_not_applicable(modifiers);

return Some(self.parse_mod_or_contract(attributes, is_contract, modifiers.visibility));
return vec![self.parse_mod_or_contract(attributes, is_contract, modifiers.visibility)];
}

if self.eat_keyword(Keyword::Struct) {
self.comptime_mutable_and_unconstrained_not_applicable(modifiers);

return Some(ItemKind::Struct(self.parse_struct(
return vec![ItemKind::Struct(self.parse_struct(
attributes,
modifiers.visibility,
start_span,
)));
))];
}

if self.eat_keyword(Keyword::Impl) {
self.comptime_mutable_and_unconstrained_not_applicable(modifiers);

return Some(match self.parse_impl() {
return vec![match self.parse_impl() {
Impl::Impl(type_impl) => ItemKind::Impl(type_impl),
Impl::TraitImpl(noir_trait_impl) => ItemKind::TraitImpl(noir_trait_impl),
});
}];
}

if self.eat_keyword(Keyword::Trait) {
self.comptime_mutable_and_unconstrained_not_applicable(modifiers);

return Some(ItemKind::Trait(self.parse_trait(
attributes,
modifiers.visibility,
start_span,
)));
let (noir_trait, noir_impl) =
self.parse_trait(attributes, modifiers.visibility, start_span);
let mut output = vec![ItemKind::Trait(noir_trait)];
if let Some(noir_impl) = noir_impl {
output.push(ItemKind::TraitImpl(noir_impl));
}

return output;
}

if self.eat_keyword(Keyword::Global) {
self.unconstrained_not_applicable(modifiers);

return Some(ItemKind::Global(
return vec![ItemKind::Global(
self.parse_global(
attributes,
modifiers.comptime.is_some(),
modifiers.mutable.is_some(),
),
modifiers.visibility,
));
)];
}

if self.eat_keyword(Keyword::Type) {
self.comptime_mutable_and_unconstrained_not_applicable(modifiers);

return Some(ItemKind::TypeAlias(
return vec![ItemKind::TypeAlias(
self.parse_type_alias(modifiers.visibility, start_span),
));
)];
}

if self.eat_keyword(Keyword::Fn) {
self.mutable_not_applicable(modifiers);

return Some(ItemKind::Function(self.parse_function(
return vec![ItemKind::Function(self.parse_function(
attributes,
modifiers.visibility,
modifiers.comptime.is_some(),
modifiers.unconstrained.is_some(),
false, // allow_self
)));
))];
}

None
vec![]
}

fn eat_mod_or_contract(&mut self) -> Option<bool> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ impl<'a> Parser<'a> {
self.parse_many_return_trailing_separator_if_any(items, separated_by, f).0
}

/// parse_many, where the given function `f` may return multiple results
pub(super) fn parse_many_to_many<T, F>(
&mut self,
items: &'static str,
separated_by: SeparatedBy,
f: F,
) -> Vec<T>
where
F: FnMut(&mut Parser<'a>) -> Vec<T>,
{
self.parse_many_to_many_return_trailing_separator_if_any(items, separated_by, f).0
}

/// Same as parse_many, but returns a bool indicating whether a trailing separator was found.
pub(super) fn parse_many_return_trailing_separator_if_any<T, F>(
&mut self,
Expand All @@ -27,6 +40,26 @@ impl<'a> Parser<'a> {
) -> (Vec<T>, bool)
where
F: FnMut(&mut Parser<'a>) -> Option<T>,
{
let f = |x: &mut Parser<'a>| {
if let Some(result) = f(x) {
vec![result]
} else {
vec![]
}
};
self.parse_many_to_many_return_trailing_separator_if_any(items, separated_by, f)
}

/// Same as parse_many, but returns a bool indicating whether a trailing separator was found.
fn parse_many_to_many_return_trailing_separator_if_any<T, F>(
&mut self,
items: &'static str,
separated_by: SeparatedBy,
mut f: F,
) -> (Vec<T>, bool)
where
F: FnMut(&mut Parser<'a>) -> Vec<T>,
{
let mut elements: Vec<T> = Vec::new();
let mut trailing_separator = false;
Expand All @@ -38,20 +71,21 @@ impl<'a> Parser<'a> {
}

let start_span = self.current_token_span;
let Some(element) = f(self) else {
let mut new_elements = f(self);
if new_elements.is_empty() {
if let Some(end) = &separated_by.until {
self.eat(end.clone());
}
break;
};
}

if let Some(separator) = &separated_by.token {
if !trailing_separator && !elements.is_empty() {
self.expected_token_separating_items(separator.clone(), items, start_span);
}
}

elements.push(element);
elements.append(&mut new_elements);

trailing_separator = if let Some(separator) = &separated_by.token {
self.eat(separator.clone())
Expand Down
Loading

0 comments on commit 1ca25e0

Please sign in to comment.