Skip to content

Commit ee7a338

Browse files
committed
feat: Add array_refcount and slice_refcount builtins for debugging (noir-lang/noir#6584)
chore!: Require types of globals to be specified (noir-lang/noir#6592) fix: don't report visibility errors when elaborating comptime value (noir-lang/noir#6498) fix: preserve newlines between comments when formatting statements (noir-lang/noir#6601) fix: parse a bit more SSA stuff (noir-lang/noir#6599) chore!: remove eddsa from stdlib (noir-lang/noir#6591) chore: Typo in oracles how to (noir-lang/noir#6598) feat(ssa): Loop invariant code motion (noir-lang/noir#6563) fix: remove `compiler_version` from new `Nargo.toml` (noir-lang/noir#6590) feat: Avoid incrementing reference counts in some cases (noir-lang/noir#6568) chore: fix typo in test name (noir-lang/noir#6589) fix: consider prereleases to be compatible with pre-1.0.0 releases (noir-lang/noir#6580) feat: try to inline brillig calls with all constant arguments (noir-lang/noir#6548) fix: correct type when simplifying `derive_pedersen_generators` (noir-lang/noir#6579) feat: Sync from aztec-packages (noir-lang/noir#6576)
2 parents d5e150c + 4fe76c4 commit ee7a338

File tree

86 files changed

+1076
-436
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+1076
-436
lines changed

.noir-sync-commit

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7216f0829dcece948d3243471e6d57380522e997
1+
45eb7568d56b2d254453b85f236d554232aa5df9

noir/noir-repo/compiler/noirc_evaluator/src/acir/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2762,6 +2762,13 @@ impl<'a> Context<'a> {
27622762
Intrinsic::FieldLessThan => {
27632763
unreachable!("FieldLessThan can only be called in unconstrained")
27642764
}
2765+
Intrinsic::ArrayRefCount | Intrinsic::SliceRefCount => {
2766+
let zero = self.acir_context.add_constant(FieldElement::zero());
2767+
Ok(vec![AcirValue::Var(
2768+
zero,
2769+
AcirType::NumericType(NumericType::Unsigned { bit_size: 32 }),
2770+
)])
2771+
}
27652772
}
27662773
}
27672774

noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs

+234-193
Large diffs are not rendered by default.

noir/noir-repo/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,18 @@ impl Context {
205205
| Intrinsic::IsUnconstrained => {}
206206
Intrinsic::ArrayLen
207207
| Intrinsic::ArrayAsStrUnchecked
208+
| Intrinsic::ArrayRefCount
208209
| Intrinsic::AsField
209210
| Intrinsic::AsSlice
210211
| Intrinsic::BlackBox(..)
211212
| Intrinsic::DerivePedersenGenerators
212213
| Intrinsic::FromField
214+
| Intrinsic::SliceInsert
213215
| Intrinsic::SlicePushBack
214216
| Intrinsic::SlicePushFront
215217
| Intrinsic::SlicePopBack
216218
| Intrinsic::SlicePopFront
217-
| Intrinsic::SliceInsert
219+
| Intrinsic::SliceRefCount
218220
| Intrinsic::SliceRemove
219221
| Intrinsic::StaticAssert
220222
| Intrinsic::StrAsBytes

noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs

+10
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ pub(crate) enum Intrinsic {
7171
IsUnconstrained,
7272
DerivePedersenGenerators,
7373
FieldLessThan,
74+
ArrayRefCount,
75+
SliceRefCount,
7476
}
7577

7678
impl std::fmt::Display for Intrinsic {
@@ -100,6 +102,8 @@ impl std::fmt::Display for Intrinsic {
100102
Intrinsic::IsUnconstrained => write!(f, "is_unconstrained"),
101103
Intrinsic::DerivePedersenGenerators => write!(f, "derive_pedersen_generators"),
102104
Intrinsic::FieldLessThan => write!(f, "field_less_than"),
105+
Intrinsic::ArrayRefCount => write!(f, "array_refcount"),
106+
Intrinsic::SliceRefCount => write!(f, "slice_refcount"),
103107
}
104108
}
105109
}
@@ -113,6 +117,10 @@ impl Intrinsic {
113117
Intrinsic::AssertConstant
114118
| Intrinsic::StaticAssert
115119
| Intrinsic::ApplyRangeConstraint
120+
// Array & slice ref counts are treated as having side effects since they operate
121+
// on hidden variables on otherwise identical array values.
122+
| Intrinsic::ArrayRefCount
123+
| Intrinsic::SliceRefCount
116124
| Intrinsic::AsWitness => true,
117125

118126
// These apply a constraint that the input must fit into a specified number of limbs.
@@ -171,6 +179,8 @@ impl Intrinsic {
171179
"is_unconstrained" => Some(Intrinsic::IsUnconstrained),
172180
"derive_pedersen_generators" => Some(Intrinsic::DerivePedersenGenerators),
173181
"field_less_than" => Some(Intrinsic::FieldLessThan),
182+
"array_refcount" => Some(Intrinsic::ArrayRefCount),
183+
"slice_refcount" => Some(Intrinsic::SliceRefCount),
174184

175185
other => BlackBoxFunc::lookup(other).map(Intrinsic::BlackBox),
176186
}

noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs

+2
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,8 @@ pub(super) fn simplify_call(
368368
SimplifyResult::None
369369
}
370370
}
371+
Intrinsic::ArrayRefCount => SimplifyResult::None,
372+
Intrinsic::SliceRefCount => SimplifyResult::None,
371373
}
372374
}
373375

noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,13 @@ fn display_constrain_error(
272272
) -> Result {
273273
match error {
274274
ConstrainError::StaticString(assert_message_string) => {
275-
writeln!(f, " '{assert_message_string:?}'")
275+
writeln!(f, ", {assert_message_string:?}")
276276
}
277277
ConstrainError::Dynamic(_, is_string, values) => {
278278
if let Some(constant_string) =
279279
try_to_extract_string_from_error_payload(*is_string, values, &function.dfg)
280280
{
281-
writeln!(f, " '{}'", constant_string)
281+
writeln!(f, ", {constant_string:?}")
282282
} else {
283283
writeln!(f, ", data {}", value_list(function, values))
284284
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ impl Context {
180180
| Intrinsic::AsWitness
181181
| Intrinsic::IsUnconstrained
182182
| Intrinsic::DerivePedersenGenerators
183+
| Intrinsic::ArrayRefCount
184+
| Intrinsic::SliceRefCount
183185
| Intrinsic::FieldLessThan => false,
184186
},
185187

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

+2
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ fn slice_capacity_change(
232232
| Intrinsic::DerivePedersenGenerators
233233
| Intrinsic::ToBits(_)
234234
| Intrinsic::ToRadix(_)
235+
| Intrinsic::ArrayRefCount
236+
| Intrinsic::SliceRefCount
235237
| Intrinsic::FieldLessThan => SizeChange::None,
236238
}
237239
}

noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/ast.rs

+7
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub(crate) enum ParsedInstruction {
8989
Constrain {
9090
lhs: ParsedValue,
9191
rhs: ParsedValue,
92+
assert_message: Option<AssertMessage>,
9293
},
9394
DecrementRc {
9495
value: ParsedValue,
@@ -129,6 +130,12 @@ pub(crate) enum ParsedInstruction {
129130
},
130131
}
131132

133+
#[derive(Debug)]
134+
pub(crate) enum AssertMessage {
135+
Static(String),
136+
Dynamic(Vec<ParsedValue>),
137+
}
138+
132139
#[derive(Debug)]
133140
pub(crate) enum ParsedTerminator {
134141
Jmp { destination: Identifier, arguments: Vec<ParsedValue> },

noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs

+34-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
use std::collections::HashMap;
22

3+
use acvm::acir::circuit::ErrorSelector;
4+
35
use crate::ssa::{
46
function_builder::FunctionBuilder,
5-
ir::{basic_block::BasicBlockId, function::FunctionId, value::ValueId},
7+
ir::{
8+
basic_block::BasicBlockId, function::FunctionId, instruction::ConstrainError,
9+
value::ValueId,
10+
},
611
};
712

813
use super::{
9-
Identifier, ParsedBlock, ParsedFunction, ParsedInstruction, ParsedSsa, ParsedTerminator,
10-
ParsedValue, RuntimeType, Ssa, SsaError,
14+
ast::AssertMessage, Identifier, ParsedBlock, ParsedFunction, ParsedInstruction, ParsedSsa,
15+
ParsedTerminator, ParsedValue, RuntimeType, Ssa, SsaError,
1116
};
1217

1318
impl ParsedSsa {
@@ -31,6 +36,8 @@ struct Translator {
3136
/// passes already which replaced some of the original IDs. The translator
3237
/// will recreate the SSA step by step, which can result in a new ID layout.
3338
variables: HashMap<FunctionId, HashMap<String, ValueId>>,
39+
40+
error_selector_counter: u64,
3441
}
3542

3643
impl Translator {
@@ -64,8 +71,13 @@ impl Translator {
6471
functions.insert(function.internal_name.clone(), function_id);
6572
}
6673

67-
let mut translator =
68-
Self { builder, functions, variables: HashMap::new(), blocks: HashMap::new() };
74+
let mut translator = Self {
75+
builder,
76+
functions,
77+
variables: HashMap::new(),
78+
blocks: HashMap::new(),
79+
error_selector_counter: 0,
80+
};
6981
translator.translate_function_body(main_function)?;
7082

7183
Ok(translator)
@@ -198,10 +210,25 @@ impl Translator {
198210
let value_id = self.builder.insert_cast(lhs, typ);
199211
self.define_variable(target, value_id)?;
200212
}
201-
ParsedInstruction::Constrain { lhs, rhs } => {
213+
ParsedInstruction::Constrain { lhs, rhs, assert_message } => {
202214
let lhs = self.translate_value(lhs)?;
203215
let rhs = self.translate_value(rhs)?;
204-
self.builder.insert_constrain(lhs, rhs, None);
216+
let assert_message = match assert_message {
217+
Some(AssertMessage::Static(string)) => {
218+
Some(ConstrainError::StaticString(string))
219+
}
220+
Some(AssertMessage::Dynamic(values)) => {
221+
let error_selector = ErrorSelector::new(self.error_selector_counter);
222+
self.error_selector_counter += 1;
223+
224+
let is_string_type = false;
225+
let values = self.translate_values(values)?;
226+
227+
Some(ConstrainError::Dynamic(error_selector, is_string_type, values))
228+
}
229+
None => None,
230+
};
231+
self.builder.insert_constrain(lhs, rhs, assert_message);
205232
}
206233
ParsedInstruction::DecrementRc { value } => {
207234
let value = self.translate_value(value)?;

noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/lexer.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ impl<'a> Lexer<'a> {
6161
Some('&') => self.single_char_token(Token::Ampersand),
6262
Some('-') if self.peek_char() == Some('>') => self.double_char_token(Token::Arrow),
6363
Some('-') => self.single_char_token(Token::Dash),
64+
Some('"') => self.eat_string_literal(),
6465
Some(ch) if ch.is_ascii_alphanumeric() || ch == '_' => self.eat_alpha_numeric(ch),
6566
Some(char) => Err(LexerError::UnexpectedCharacter {
6667
char,
@@ -177,6 +178,41 @@ impl<'a> Lexer<'a> {
177178
Ok(integer_token.into_span(start, end))
178179
}
179180

181+
fn eat_string_literal(&mut self) -> SpannedTokenResult {
182+
let start = self.position;
183+
let mut string = String::new();
184+
185+
while let Some(next) = self.next_char() {
186+
let char = match next {
187+
'"' => break,
188+
'\\' => match self.next_char() {
189+
Some('r') => '\r',
190+
Some('n') => '\n',
191+
Some('t') => '\t',
192+
Some('0') => '\0',
193+
Some('"') => '"',
194+
Some('\\') => '\\',
195+
Some(escaped) => {
196+
let span = Span::inclusive(start, self.position);
197+
return Err(LexerError::InvalidEscape { escaped, span });
198+
}
199+
None => {
200+
let span = Span::inclusive(start, self.position);
201+
return Err(LexerError::UnterminatedStringLiteral { span });
202+
}
203+
},
204+
other => other,
205+
};
206+
207+
string.push(char);
208+
}
209+
210+
let str_literal_token = Token::Str(string);
211+
212+
let end = self.position;
213+
Ok(str_literal_token.into_span(start, end))
214+
}
215+
180216
fn eat_while<F: Fn(char) -> bool>(
181217
&mut self,
182218
initial_char: Option<char>,
@@ -247,14 +283,22 @@ pub(crate) enum LexerError {
247283
InvalidIntegerLiteral { span: Span, found: String },
248284
#[error("Integer literal too large")]
249285
IntegerLiteralTooLarge { span: Span, limit: String },
286+
#[error("Unterminated string literal")]
287+
UnterminatedStringLiteral { span: Span },
288+
#[error(
289+
"'\\{escaped}' is not a valid escape sequence. Use '\\' for a literal backslash character."
290+
)]
291+
InvalidEscape { escaped: char, span: Span },
250292
}
251293

252294
impl LexerError {
253295
pub(crate) fn span(&self) -> Span {
254296
match self {
255297
LexerError::UnexpectedCharacter { span, .. }
256298
| LexerError::InvalidIntegerLiteral { span, .. }
257-
| LexerError::IntegerLiteralTooLarge { span, .. } => *span,
299+
| LexerError::IntegerLiteralTooLarge { span, .. }
300+
| LexerError::UnterminatedStringLiteral { span }
301+
| LexerError::InvalidEscape { span, .. } => *span,
258302
}
259303
}
260304
}

noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/mod.rs

+42-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use super::{
1010

1111
use acvm::{AcirField, FieldElement};
1212
use ast::{
13-
Identifier, ParsedBlock, ParsedFunction, ParsedInstruction, ParsedParameter, ParsedSsa,
14-
ParsedValue,
13+
AssertMessage, Identifier, ParsedBlock, ParsedFunction, ParsedInstruction, ParsedParameter,
14+
ParsedSsa, ParsedValue,
1515
};
1616
use lexer::{Lexer, LexerError};
1717
use noirc_errors::Span;
@@ -313,7 +313,20 @@ impl<'a> Parser<'a> {
313313
let lhs = self.parse_value_or_error()?;
314314
self.eat_or_error(Token::Equal)?;
315315
let rhs = self.parse_value_or_error()?;
316-
Ok(Some(ParsedInstruction::Constrain { lhs, rhs }))
316+
317+
let assert_message = if self.eat(Token::Comma)? {
318+
if let Some(str) = self.eat_str()? {
319+
Some(AssertMessage::Static(str))
320+
} else if self.eat_keyword(Keyword::Data)? {
321+
Some(AssertMessage::Dynamic(self.parse_comma_separated_values()?))
322+
} else {
323+
return self.expected_string_or_data();
324+
}
325+
} else {
326+
None
327+
};
328+
329+
Ok(Some(ParsedInstruction::Constrain { lhs, rhs, assert_message }))
317330
}
318331

319332
fn parse_decrement_rc(&mut self) -> ParseResult<Option<ParsedInstruction>> {
@@ -654,6 +667,10 @@ impl<'a> Parser<'a> {
654667
return Ok(Type::Reference(Arc::new(typ)));
655668
}
656669

670+
if self.eat_keyword(Keyword::Function)? {
671+
return Ok(Type::Function);
672+
}
673+
657674
self.expected_type()
658675
}
659676

@@ -767,6 +784,18 @@ impl<'a> Parser<'a> {
767784
}
768785
}
769786

787+
fn eat_str(&mut self) -> ParseResult<Option<String>> {
788+
if matches!(self.token.token(), Token::Str(..)) {
789+
let token = self.bump()?;
790+
match token.into_token() {
791+
Token::Str(string) => Ok(Some(string)),
792+
_ => unreachable!(),
793+
}
794+
} else {
795+
Ok(None)
796+
}
797+
}
798+
770799
fn eat(&mut self, token: Token) -> ParseResult<bool> {
771800
if self.token.token() == &token {
772801
self.bump()?;
@@ -812,6 +841,13 @@ impl<'a> Parser<'a> {
812841
})
813842
}
814843

844+
fn expected_string_or_data<T>(&mut self) -> ParseResult<T> {
845+
Err(ParserError::ExpectedStringOrData {
846+
found: self.token.token().clone(),
847+
span: self.token.to_span(),
848+
})
849+
}
850+
815851
fn expected_identifier<T>(&mut self) -> ParseResult<T> {
816852
Err(ParserError::ExpectedIdentifier {
817853
found: self.token.token().clone(),
@@ -873,6 +909,8 @@ pub(crate) enum ParserError {
873909
ExpectedType { found: Token, span: Span },
874910
#[error("Expected an instruction or terminator, found '{found}'")]
875911
ExpectedInstructionOrTerminator { found: Token, span: Span },
912+
#[error("Expected a string literal or 'data', found '{found}'")]
913+
ExpectedStringOrData { found: Token, span: Span },
876914
#[error("Expected a value, found '{found}'")]
877915
ExpectedValue { found: Token, span: Span },
878916
#[error("Multiple return values only allowed for call")]
@@ -889,6 +927,7 @@ impl ParserError {
889927
| ParserError::ExpectedInt { span, .. }
890928
| ParserError::ExpectedType { span, .. }
891929
| ParserError::ExpectedInstructionOrTerminator { span, .. }
930+
| ParserError::ExpectedStringOrData { span, .. }
892931
| ParserError::ExpectedValue { span, .. } => *span,
893932
ParserError::MultipleReturnValuesOnlyAllowedForCall { second_target, .. } => {
894933
second_target.span

0 commit comments

Comments
 (0)