Skip to content

Commit 1ca25e0

Browse files
committed
feat: trait aliases (noir-lang/noir#6431)
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)
2 parents 57b4735 + ba1d3a3 commit 1ca25e0

File tree

19 files changed

+1242
-110
lines changed

19 files changed

+1242
-110
lines changed

.noir-sync-commit

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
29d46fd36aaf0da7041973f3c0e49096bd978adc
1+
68c32b4ffd9b069fe4b119327dbf4018c17ab9d4

noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs

+228-53
Large diffs are not rendered by default.

noir/noir-repo/compiler/noirc_frontend/src/ast/traits.rs

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub struct NoirTrait {
2424
pub items: Vec<Documented<TraitItem>>,
2525
pub attributes: Vec<SecondaryAttribute>,
2626
pub visibility: ItemVisibility,
27+
pub is_alias: bool,
2728
}
2829

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

7980
pub items: Vec<Documented<TraitImplItem>>,
81+
82+
/// true if generated at compile-time, e.g. from a trait alias
83+
pub is_synthetic: bool,
8084
}
8185

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

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

138143
write!(f, "trait {}{}", self.name, generics)?;
144+
145+
if self.is_alias {
146+
let bounds = vecmap(&self.bounds, |bound| bound.to_string()).join(" + ");
147+
return write!(f, " = {};", bounds);
148+
}
149+
139150
if !self.bounds.is_empty() {
140151
let bounds = vecmap(&self.bounds, |bound| bound.to_string()).join(" + ");
141152
write!(f, ": {}", bounds)?;
@@ -222,6 +233,11 @@ impl Display for TraitBound {
222233

223234
impl Display for NoirTraitImpl {
224235
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236+
// Synthetic NoirTraitImpl's don't get printed
237+
if self.is_synthetic {
238+
return Ok(());
239+
}
240+
225241
write!(f, "impl")?;
226242
if !self.impl_generics.is_empty() {
227243
write!(

noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ pub enum TypeCheckError {
208208

209209
#[derive(Debug, Clone, PartialEq, Eq)]
210210
pub struct NoMatchingImplFoundError {
211-
constraints: Vec<(Type, String)>,
211+
pub(crate) constraints: Vec<(Type, String)>,
212212
pub span: Span,
213213
}
214214

noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ pub enum ParserErrorReason {
9595
AssociatedTypesNotAllowedInPaths,
9696
#[error("Associated types are not allowed on a method call")]
9797
AssociatedTypesNotAllowedInMethodCalls,
98+
#[error("Empty trait alias")]
99+
EmptyTraitAlias,
98100
#[error(
99101
"Wrong number of arguments for attribute `{}`. Expected {}, found {}",
100102
name,

noir/noir-repo/compiler/noirc_frontend/src/parser/parser/impls.rs

+2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ impl<'a> Parser<'a> {
113113
let object_type = self.parse_type_or_error();
114114
let where_clause = self.parse_where_clause();
115115
let items = self.parse_trait_impl_body();
116+
let is_synthetic = false;
116117

117118
NoirTraitImpl {
118119
impl_generics,
@@ -121,6 +122,7 @@ impl<'a> Parser<'a> {
121122
object_type,
122123
where_clause,
123124
items,
125+
is_synthetic,
124126
}
125127
}
126128

noir/noir-repo/compiler/noirc_frontend/src/parser/parser/item.rs

+41-31
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use iter_extended::vecmap;
2+
13
use crate::{
24
parser::{labels::ParsingRuleLabel, Item, ItemKind},
35
token::{Keyword, Token},
@@ -13,31 +15,32 @@ impl<'a> Parser<'a> {
1315
}
1416

1517
pub(crate) fn parse_module_items(&mut self, nested: bool) -> Vec<Item> {
16-
self.parse_many("items", without_separator(), |parser| {
18+
self.parse_many_to_many("items", without_separator(), |parser| {
1719
parser.parse_module_item_in_list(nested)
1820
})
1921
}
2022

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

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

34-
let Some(item) = self.parse_item() else {
36+
let parsed_items = self.parse_item();
37+
if parsed_items.is_empty() {
3538
// If we couldn't parse an item we check which token we got
3639
match self.token.token() {
3740
Token::RightBrace if nested => {
38-
return None;
41+
return vec![];
3942
}
40-
Token::EOF => return None,
43+
Token::EOF => return vec![],
4144
_ => (),
4245
}
4346

@@ -47,7 +50,7 @@ impl<'a> Parser<'a> {
4750
continue;
4851
};
4952

50-
return Some(item);
53+
return parsed_items;
5154
}
5255
}
5356

@@ -85,15 +88,19 @@ impl<'a> Parser<'a> {
8588
}
8689

8790
/// Item = OuterDocComments ItemKind
88-
fn parse_item(&mut self) -> Option<Item> {
91+
fn parse_item(&mut self) -> Vec<Item> {
8992
let start_span = self.current_token_span;
9093
let doc_comments = self.parse_outer_doc_comments();
91-
let kind = self.parse_item_kind()?;
94+
let kinds = self.parse_item_kind();
9295
let span = self.span_since(start_span);
9396

94-
Some(Item { kind, span, doc_comments })
97+
vecmap(kinds, |kind| Item { kind, span, doc_comments: doc_comments.clone() })
9598
}
9699

100+
/// This method returns one 'ItemKind' in the majority of cases.
101+
/// The current exception is when parsing a trait alias,
102+
/// which returns both the trait and the impl.
103+
///
97104
/// ItemKind
98105
/// = InnerAttribute
99106
/// | Attributes Modifiers
@@ -106,9 +113,9 @@ impl<'a> Parser<'a> {
106113
/// | TypeAlias
107114
/// | Function
108115
/// )
109-
fn parse_item_kind(&mut self) -> Option<ItemKind> {
116+
fn parse_item_kind(&mut self) -> Vec<ItemKind> {
110117
if let Some(kind) = self.parse_inner_attribute() {
111-
return Some(ItemKind::InnerAttribute(kind));
118+
return vec![ItemKind::InnerAttribute(kind)];
112119
}
113120

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

124131
let use_tree = self.parse_use_tree();
125-
return Some(ItemKind::Import(use_tree, modifiers.visibility));
132+
return vec![ItemKind::Import(use_tree, modifiers.visibility)];
126133
}
127134

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

131-
return Some(self.parse_mod_or_contract(attributes, is_contract, modifiers.visibility));
138+
return vec![self.parse_mod_or_contract(attributes, is_contract, modifiers.visibility)];
132139
}
133140

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

137-
return Some(ItemKind::Struct(self.parse_struct(
144+
return vec![ItemKind::Struct(self.parse_struct(
138145
attributes,
139146
modifiers.visibility,
140147
start_span,
141-
)));
148+
))];
142149
}
143150

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

147-
return Some(match self.parse_impl() {
154+
return vec![match self.parse_impl() {
148155
Impl::Impl(type_impl) => ItemKind::Impl(type_impl),
149156
Impl::TraitImpl(noir_trait_impl) => ItemKind::TraitImpl(noir_trait_impl),
150-
});
157+
}];
151158
}
152159

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

156-
return Some(ItemKind::Trait(self.parse_trait(
157-
attributes,
158-
modifiers.visibility,
159-
start_span,
160-
)));
163+
let (noir_trait, noir_impl) =
164+
self.parse_trait(attributes, modifiers.visibility, start_span);
165+
let mut output = vec![ItemKind::Trait(noir_trait)];
166+
if let Some(noir_impl) = noir_impl {
167+
output.push(ItemKind::TraitImpl(noir_impl));
168+
}
169+
170+
return output;
161171
}
162172

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

166-
return Some(ItemKind::Global(
176+
return vec![ItemKind::Global(
167177
self.parse_global(
168178
attributes,
169179
modifiers.comptime.is_some(),
170180
modifiers.mutable.is_some(),
171181
),
172182
modifiers.visibility,
173-
));
183+
)];
174184
}
175185

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

179-
return Some(ItemKind::TypeAlias(
189+
return vec![ItemKind::TypeAlias(
180190
self.parse_type_alias(modifiers.visibility, start_span),
181-
));
191+
)];
182192
}
183193

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

187-
return Some(ItemKind::Function(self.parse_function(
197+
return vec![ItemKind::Function(self.parse_function(
188198
attributes,
189199
modifiers.visibility,
190200
modifiers.comptime.is_some(),
191201
modifiers.unconstrained.is_some(),
192202
false, // allow_self
193-
)));
203+
))];
194204
}
195205

196-
None
206+
vec![]
197207
}
198208

199209
fn eat_mod_or_contract(&mut self) -> Option<bool> {

noir/noir-repo/compiler/noirc_frontend/src/parser/parser/parse_many.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,19 @@ impl<'a> Parser<'a> {
1818
self.parse_many_return_trailing_separator_if_any(items, separated_by, f).0
1919
}
2020

21+
/// parse_many, where the given function `f` may return multiple results
22+
pub(super) fn parse_many_to_many<T, F>(
23+
&mut self,
24+
items: &'static str,
25+
separated_by: SeparatedBy,
26+
f: F,
27+
) -> Vec<T>
28+
where
29+
F: FnMut(&mut Parser<'a>) -> Vec<T>,
30+
{
31+
self.parse_many_to_many_return_trailing_separator_if_any(items, separated_by, f).0
32+
}
33+
2134
/// Same as parse_many, but returns a bool indicating whether a trailing separator was found.
2235
pub(super) fn parse_many_return_trailing_separator_if_any<T, F>(
2336
&mut self,
@@ -27,6 +40,26 @@ impl<'a> Parser<'a> {
2740
) -> (Vec<T>, bool)
2841
where
2942
F: FnMut(&mut Parser<'a>) -> Option<T>,
43+
{
44+
let f = |x: &mut Parser<'a>| {
45+
if let Some(result) = f(x) {
46+
vec![result]
47+
} else {
48+
vec![]
49+
}
50+
};
51+
self.parse_many_to_many_return_trailing_separator_if_any(items, separated_by, f)
52+
}
53+
54+
/// Same as parse_many, but returns a bool indicating whether a trailing separator was found.
55+
fn parse_many_to_many_return_trailing_separator_if_any<T, F>(
56+
&mut self,
57+
items: &'static str,
58+
separated_by: SeparatedBy,
59+
mut f: F,
60+
) -> (Vec<T>, bool)
61+
where
62+
F: FnMut(&mut Parser<'a>) -> Vec<T>,
3063
{
3164
let mut elements: Vec<T> = Vec::new();
3265
let mut trailing_separator = false;
@@ -38,20 +71,21 @@ impl<'a> Parser<'a> {
3871
}
3972

4073
let start_span = self.current_token_span;
41-
let Some(element) = f(self) else {
74+
let mut new_elements = f(self);
75+
if new_elements.is_empty() {
4276
if let Some(end) = &separated_by.until {
4377
self.eat(end.clone());
4478
}
4579
break;
46-
};
80+
}
4781

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

54-
elements.push(element);
88+
elements.append(&mut new_elements);
5589

5690
trailing_separator = if let Some(separator) = &separated_by.token {
5791
self.eat(separator.clone())

0 commit comments

Comments
 (0)