Skip to content

Commit

Permalink
fix: set local_module before elaborating each trait (noir-lang/noir#6506
Browse files Browse the repository at this point in the history
)

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 13, 2024
2 parents 6470736 + 1c072e4 commit 04d78e9
Show file tree
Hide file tree
Showing 23 changed files with 171 additions and 126 deletions.
2 changes: 1 addition & 1 deletion .noir-sync-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
72e8de0656c4789f57ff1d3ddecc8901df627aab
1df8c456d6d256f120d6df6ae3e6735cb7eb7dae
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ mod tests {
public_parameters: PublicInputs::default(),
return_values: PublicInputs::default(),
assert_messages: Default::default(),
recursive: false,
};
check_circuit(circuit);
}
Expand Down Expand Up @@ -347,6 +348,7 @@ mod tests {
public_parameters: PublicInputs::default(),
return_values: PublicInputs::default(),
assert_messages: Default::default(),
recursive: false,
};
check_circuit(circuit);
}
Expand Down
1 change: 1 addition & 0 deletions noir/noir-repo/acvm-repo/acvm/src/compiler/simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ mod tests {
public_parameters,
return_values: PublicInputs::default(),
assert_messages: Default::default(),
recursive: false,
}
}

Expand Down
26 changes: 10 additions & 16 deletions noir/noir-repo/compiler/noirc_driver/src/abi_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use noirc_abi::{
Abi, AbiErrorType, AbiParameter, AbiReturnType, AbiType, AbiValue, AbiVisibility, Sign,
};
use noirc_errors::Span;
use noirc_evaluator::ssa::ErrorType;
use noirc_frontend::ast::{Signedness, Visibility};
use noirc_frontend::TypeBinding;
use noirc_frontend::{
Expand Down Expand Up @@ -50,22 +49,17 @@ fn get_main_function_span(context: &Context) -> Span {
}
}

fn build_abi_error_type(context: &Context, typ: ErrorType) -> AbiErrorType {
fn build_abi_error_type(context: &Context, typ: &Type) -> AbiErrorType {
match typ {
ErrorType::Dynamic(typ) => {
if let Type::FmtString(len, item_types) = typ {
let length = len
.evaluate_to_u32(get_main_function_span(context))
.expect("Cannot evaluate fmt length");
let Type::Tuple(item_types) = item_types.as_ref() else {
unreachable!("FmtString items must be a tuple")
};
let item_types =
item_types.iter().map(|typ| abi_type_from_hir_type(context, typ)).collect();
AbiErrorType::FmtString { length, item_types }
} else {
AbiErrorType::Custom(abi_type_from_hir_type(context, &typ))
}
Type::FmtString(len, item_types) => {
let span = get_main_function_span(context);
let length = len.evaluate_to_u32(span).expect("Cannot evaluate fmt length");
let Type::Tuple(item_types) = item_types.as_ref() else {
unreachable!("FmtString items must be a tuple")
};
let item_types =
item_types.iter().map(|typ| abi_type_from_hir_type(context, typ)).collect();
AbiErrorType::FmtString { length, item_types }
}
ErrorType::String(string) => AbiErrorType::String { string },
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ use acvm::acir::brillig::Opcode as BrilligOpcode;
use acvm::acir::circuit::ErrorSelector;
use std::collections::{BTreeMap, HashMap};

use crate::ssa::ir::{
basic_block::BasicBlockId, dfg::CallStack, function::FunctionId, instruction::ErrorType,
};
use crate::ssa::ir::{basic_block::BasicBlockId, dfg::CallStack, function::FunctionId};

use super::procedures::ProcedureId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use mem_copy::compile_mem_copy_procedure;
use noirc_errors::debug_info::ProcedureDebugId;
use prepare_vector_insert::compile_prepare_vector_insert_procedure;
use prepare_vector_push::compile_prepare_vector_push_procedure;
use revert_with_string::compile_revert_with_string_procedure;
use serde::{Deserialize, Serialize};
use vector_copy::compile_vector_copy_procedure;
use vector_pop_back::compile_vector_pop_back_procedure;
Expand All @@ -35,7 +34,7 @@ use super::{
/// Procedures are a set of complex operations that are common in the noir language.
/// Extracting them to reusable procedures allows us to reduce the size of the generated Brillig.
/// Procedures receive their arguments on scratch space to avoid stack dumping&restoring.
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Deserialize, Serialize)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, Deserialize, Serialize)]
pub enum ProcedureId {
ArrayCopy,
ArrayReverse,
Expand Down Expand Up @@ -107,11 +106,64 @@ impl std::fmt::Display for ProcedureId {
}
}

impl ProcedureId {
pub(crate) fn to_debug_id(self) -> ProcedureDebugId {
ProcedureDebugId(match self {
ProcedureId::ArrayCopy => 0,
ProcedureId::ArrayReverse => 1,
ProcedureId::VectorCopy => 2,
ProcedureId::MemCopy => 3,
ProcedureId::PrepareVectorPush(true) => 4,
ProcedureId::PrepareVectorPush(false) => 5,
ProcedureId::VectorPopFront => 6,
ProcedureId::VectorPopBack => 7,
ProcedureId::PrepareVectorInsert => 8,
ProcedureId::VectorRemove => 9,
ProcedureId::CheckMaxStackDepth => 10,
})
}

pub fn from_debug_id(debug_id: ProcedureDebugId) -> Self {
let inner = debug_id.0;
match inner {
0 => ProcedureId::ArrayCopy,
1 => ProcedureId::ArrayReverse,
2 => ProcedureId::VectorCopy,
3 => ProcedureId::MemCopy,
4 => ProcedureId::PrepareVectorPush(true),
5 => ProcedureId::PrepareVectorPush(false),
6 => ProcedureId::VectorPopFront,
7 => ProcedureId::VectorPopBack,
8 => ProcedureId::PrepareVectorInsert,
9 => ProcedureId::VectorRemove,
10 => ProcedureId::CheckMaxStackDepth,
_ => panic!("Unsupported procedure debug ID of {inner} was supplied"),
}
}
}

impl std::fmt::Display for ProcedureId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ProcedureId::ArrayCopy => write!(f, "ArrayCopy"),
ProcedureId::ArrayReverse => write!(f, "ArrayReverse"),
ProcedureId::VectorCopy => write!(f, "VectorCopy"),
ProcedureId::MemCopy => write!(f, "MemCopy"),
ProcedureId::PrepareVectorPush(flag) => write!(f, "PrepareVectorPush({flag})"),
ProcedureId::VectorPopFront => write!(f, "VectorPopFront"),
ProcedureId::VectorPopBack => write!(f, "VectorPopBack"),
ProcedureId::PrepareVectorInsert => write!(f, "PrepareVectorInsert"),
ProcedureId::VectorRemove => write!(f, "VectorRemove"),
ProcedureId::CheckMaxStackDepth => write!(f, "CheckMaxStackDepth"),
}
}
}

pub(crate) fn compile_procedure<F: AcirField + DebugToString>(
procedure_id: ProcedureId,
) -> BrilligArtifact<F> {
let mut brillig_context = BrilligContext::new_for_procedure(false, procedure_id.clone());
brillig_context.enter_context(Label::procedure(procedure_id.clone()));
let mut brillig_context = BrilligContext::new_for_procedure(false, procedure_id);
brillig_context.enter_context(Label::procedure(procedure_id));

match procedure_id {
ProcedureId::MemCopy => compile_mem_copy_procedure(&mut brillig_context),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1010,13 +1010,13 @@ impl<'a> Context<'a> {
};
entry_point.link_with(artifact);
// Insert the range of opcode locations occupied by a procedure
if let Some(procedure_id) = &artifact.procedure {
if let Some(procedure_id) = artifact.procedure {
let num_opcodes = entry_point.byte_code.len();
let previous_num_opcodes = entry_point.byte_code.len() - artifact.byte_code.len();
// We subtract one as to keep the range inclusive on both ends
entry_point
.procedure_locations
.insert(procedure_id.clone(), (previous_num_opcodes, num_opcodes - 1));
.insert(procedure_id, (previous_num_opcodes, num_opcodes - 1));
}
}
// Generate the final bytecode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,13 +453,7 @@ impl FunctionBuilder {
match self.type_of_value(value) {
Type::Numeric(_) => (),
Type::Function => (),
Type::Reference(element) => {
if element.contains_an_array() {
let reference = value;
let value = self.insert_load(reference, element.as_ref().clone());
self.update_array_reference_count(value, increment);
}
}
Type::Reference(_) => (),
Type::Array(..) | Type::Slice(..) => {
// If there are nested arrays or slices, we wait until ArrayGet
// is issued to increment the count of that array.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,34 @@ fn replace_known_slice_lengths(
func.dfg.set_value_from_id(original_slice_length, known_length);
});
}

#[cfg(test)]
mod test {
use crate::ssa::opt::assert_normalized_ssa_equals;

use super::Ssa;

#[test]
fn as_slice_length_optimization() {
// In this code we expect `return v2` to be replaced with `return u32 3` because
// that's the length of the v0 array.
let src = "
acir(inline) fn main f0 {
b0(v0: [Field; 3]):
v2, v3 = call as_slice(v0) -> (u32, [Field])
return v2
}
";
let ssa = Ssa::from_str(src).unwrap();

let expected = "
acir(inline) fn main f0 {
b0(v0: [Field; 3]):
v2, v3 = call as_slice(v0) -> (u32, [Field])
return u32 3
}
";
let ssa = ssa.as_slice_optimization();
assert_normalized_ssa_equals(ssa, expected);
}
}
32 changes: 18 additions & 14 deletions noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ impl Debug for SsaErrorWithSource {
pub(crate) enum SsaError {
#[error("{0}")]
ParserError(ParserError),
#[error("Unknown variable `{0}`")]
#[error("Unknown variable '{0}'")]
UnknownVariable(Identifier),
#[error("Unknown block `{0}`")]
#[error("Unknown block '{0}'")]
UnknownBlock(Identifier),
#[error("Unknown function `{0}`")]
#[error("Unknown function '{0}'")]
UnknownFunction(Identifier),
#[error("Mismatched return values")]
MismatchedReturnValues { returns: Vec<Identifier>, expected: usize },
#[error("Variable `{0}` already defined")]
#[error("Variable '{0}' already defined")]
VariableAlreadyDefined(Identifier),
}

Expand Down Expand Up @@ -647,10 +647,14 @@ impl<'a> Parser<'a> {

if self.eat(Token::LeftBracket)? {
let element_types = self.parse_types()?;
self.eat_or_error(Token::Semicolon)?;
let length = self.eat_int_or_error()?;
self.eat_or_error(Token::RightBracket)?;
return Ok(Type::Array(Arc::new(element_types), length.to_u128() as usize));
if self.eat(Token::Semicolon)? {
let length = self.eat_int_or_error()?;
self.eat_or_error(Token::RightBracket)?;
return Ok(Type::Array(Arc::new(element_types), length.to_u128() as usize));
} else {
self.eat_or_error(Token::RightBracket)?;
return Ok(Type::Slice(Arc::new(element_types)));
}
}

if let Some(typ) = self.parse_mutable_reference_type()? {
Expand Down Expand Up @@ -857,19 +861,19 @@ impl<'a> Parser<'a> {
pub(crate) enum ParserError {
#[error("{0}")]
LexerError(LexerError),
#[error("Expected {token}, found {token}")]
#[error("Expected '{token}', found '{found}'")]
ExpectedToken { token: Token, found: Token, span: Span },
#[error("Expected one of {tokens:?}, found {found}")]
ExpectedOneOfTokens { tokens: Vec<Token>, found: Token, span: Span },
#[error("Expected an identifier, found {found}")]
#[error("Expected an identifier, found '{found}'")]
ExpectedIdentifier { found: Token, span: Span },
#[error("Expected an int, found {found}")]
#[error("Expected an int, found '{found}'")]
ExpectedInt { found: Token, span: Span },
#[error("Expected a type, found {found}")]
#[error("Expected a type, found '{found}'")]
ExpectedType { found: Token, span: Span },
#[error("Expected an instruction or terminator, found {found}")]
#[error("Expected an instruction or terminator, found '{found}'")]
ExpectedInstructionOrTerminator { found: Token, span: Span },
#[error("Expected a value, found {found}")]
#[error("Expected a value, found '{found}'")]
ExpectedValue { found: Token, span: Span },
#[error("Multiple return values only allowed for call")]
MultipleReturnValuesOnlyAllowedForCall { second_target: Identifier },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ type SpannedTokenResult = Result<SpannedToken, LexerError>;

#[derive(Debug, Error)]
pub(crate) enum LexerError {
#[error("Unexpected character: {char}")]
#[error("Unexpected character: {char:?}")]
UnexpectedCharacter { char: char, span: Span },
#[error("Invalid integer literal")]
InvalidIntegerLiteral { span: Span, found: String },
Expand Down
12 changes: 12 additions & 0 deletions noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,15 @@ fn test_parses_with_comments() {
let ssa = Ssa::from_str(src).unwrap();
assert_normalized_ssa_equals(ssa, expected);
}

#[test]
fn test_slice() {
let src = "
acir(inline) fn main f0 {
b0(v0: [Field; 3]):
v2, v3 = call as_slice(v0) -> (u32, [Field])
return
}
";
assert_ssa_roundtrip(src);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use super::Elaborator;
impl<'context> Elaborator<'context> {
pub fn collect_traits(&mut self, traits: &BTreeMap<TraitId, UnresolvedTrait>) {
for (trait_id, unresolved_trait) in traits {
self.local_module = unresolved_trait.module_id;

self.recover_generics(|this| {
this.current_trait = Some(*trait_id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ impl<'a> Parser<'a> {
"oracle" => self.parse_single_name_attribute(ident, arguments, start_span, |name| {
Attribute::Function(FunctionAttribute::Oracle(name))
}),
"recursive" => {
let attr = Attribute::Function(FunctionAttribute::Recursive);
self.parse_no_args_attribute(ident, arguments, attr)
}
"use_callers_scope" => {
let attr = Attribute::Secondary(SecondaryAttribute::UseCallersScope);
self.parse_no_args_attribute(ident, arguments, attr)
Expand Down Expand Up @@ -500,6 +504,13 @@ mod tests {
parse_attribute_no_errors(src, expected);
}

#[test]
fn parses_attribute_recursive() {
let src = "#[recursive]";
let expected = Attribute::Function(FunctionAttribute::Recursive);
parse_attribute_no_errors(src, expected);
}

#[test]
fn parses_attribute_fold() {
let src = "#[fold]";
Expand Down
20 changes: 20 additions & 0 deletions noir/noir-repo/compiler/noirc_frontend/src/tests/unused_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,23 @@ fn no_warning_on_self_in_trait_impl() {
"#;
assert_no_errors(src);
}

#[test]
fn resolves_trait_where_clause_in_the_correct_module() {
// This is a regression test for https://github.com/noir-lang/noir/issues/6479
let src = r#"
mod foo {
pub trait Foo {}
}
use foo::Foo;
pub trait Bar<T>
where
T: Foo,
{}
fn main() {}
"#;
assert_no_errors(src);
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit 04d78e9

Please sign in to comment.