From 6f6217f45bf36a4a21184fde8e9733989f19538b Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:14:18 +0000 Subject: [PATCH 01/38] create a namespaced API for macros --- compiler/noirc_frontend/src/lib.rs | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/compiler/noirc_frontend/src/lib.rs b/compiler/noirc_frontend/src/lib.rs index 74057240de1..77107d3e7db 100644 --- a/compiler/noirc_frontend/src/lib.rs +++ b/compiler/noirc_frontend/src/lib.rs @@ -34,3 +34,46 @@ pub use hir_def::types::*; // Unit tests that involve all modules pub mod tests; + +// API for experimental macros feature +pub mod macros_api { + + pub use acvm::FieldElement; + pub use fm::FileId; + pub use noirc_errors::Span; + + pub use crate::graph::CrateId; + pub use crate::hir::def_collector::errors::MacroError; + pub use crate::hir_def::expr::{HirExpression, HirLiteral}; + pub use crate::hir_def::stmt::HirStatement; + pub use crate::node_interner::{NodeInterner, StructId}; + pub use crate::parser::SortedModule; + pub use crate::token::SecondaryAttribute; + + pub use crate::hir::def_map::ModuleDefId; + pub use crate::{ + hir::Context as HirContext, BlockExpression, CallExpression, CastExpression, Distinctness, + Expression, ExpressionKind, FunctionReturnType, Ident, IndexExpression, LetStatement, + Literal, MemberAccessExpression, MethodCallExpression, NoirFunction, Path, PathKind, + Pattern, Statement, UnresolvedType, UnresolvedTypeData, Visibility, + }; + pub use crate::{ + ForLoopStatement, ForRange, FunctionDefinition, FunctionVisibility, ImportStatement, + NoirStruct, Param, PrefixExpression, Signedness, StatementKind, StructType, Type, TypeImpl, + UnaryOp, + }; + + /// Methods to process the AST before and after type checking + pub trait MacroProcessor { + /// Function to manipulate the AST before type checking has been completed. + fn process_untyped_ast( + &self, + ast: SortedModule, + crate_id: &CrateId, + context: &HirContext, + ) -> Result; + /// Function to manipulate the AST after type checking has been completed. + /// The AST after type checking has been done is called the HIR. + fn process_typed_ast(&self, crate_id: &CrateId, context: &mut HirContext); + } +} From 1212b44eeb8300c37b2b4d43e355f55a61e5434f Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:15:33 +0000 Subject: [PATCH 02/38] remove aztec specific error variants --- .../src/hir/def_collector/errors.rs | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/errors.rs b/compiler/noirc_frontend/src/hir/def_collector/errors.rs index edb39fe68d7..2b91c4b36c5 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/errors.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/errors.rs @@ -73,15 +73,16 @@ pub enum DefCollectorErrorKind { "Either the type or the trait must be from the same crate as the trait implementation" )] TraitImplOrphaned { span: Span }, + #[error("macro error : {0:?}")] + MacroError(MacroError), +} - // Aztec feature flag errors - // TODO(benesjan): https://github.com/AztecProtocol/aztec-packages/issues/2905 - #[cfg(feature = "aztec")] - #[error("Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml")] - AztecNotFound {}, - #[cfg(feature = "aztec")] - #[error("compute_note_hash_and_nullifier function not found. Define it in your contract.")] - AztecComputeNoteHashAndNullifierNotFound { span: Span }, +/// An error struct that macro processors can return. +#[derive(Debug, Clone)] +pub struct MacroError { + pub primary_message: String, + pub secondary_message: Option, + pub span: Option, } impl DefCollectorErrorKind { @@ -245,16 +246,9 @@ impl From for Diagnostic { "Either the type or the trait must be from the same crate as the trait implementation".into(), span, ), - #[cfg(feature = "aztec")] - DefCollectorErrorKind::AztecNotFound {} => Diagnostic::from_message( - "Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml", - ), - #[cfg(feature = "aztec")] - DefCollectorErrorKind::AztecComputeNoteHashAndNullifierNotFound {span} => Diagnostic::simple_error( - "compute_note_hash_and_nullifier function not found. Define it in your contract.".into(), - "".into(), - span - ), + DefCollectorErrorKind::MacroError(macro_error) => { + Diagnostic::simple_error(macro_error.primary_message, macro_error.secondary_message.unwrap_or_default(), macro_error.span.unwrap_or_default()) + }, } } } From 837354101342ea97258be38b38428ed436b0a97e Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:16:36 +0000 Subject: [PATCH 03/38] remove aztec feature flag from frontend by allowing arbitrary macro processing functions --- .../src/hir/def_collector/dc_crate.rs | 11 ++++---- .../noirc_frontend/src/hir/def_map/mod.rs | 28 +++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index ce1cf675a07..e3105342db2 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -13,6 +13,7 @@ use crate::hir::resolution::{ use crate::hir::type_check::{type_check_func, TypeCheckError, TypeChecker}; use crate::hir::Context; use crate::hir_def::traits::{Trait, TraitConstant, TraitFunction, TraitImpl, TraitType}; +use crate::macros_api::MacroProcessor; use crate::node_interner::{ FuncId, NodeInterner, StmtId, StructId, TraitId, TraitImplId, TypeAliasId, }; @@ -199,6 +200,7 @@ impl DefCollector { context: &mut Context, ast: SortedModule, root_file_id: FileId, + macro_processors: &[impl MacroProcessor], ) -> Vec<(CompilationError, FileId)> { let mut errors: Vec<(CompilationError, FileId)> = vec![]; let crate_id = def_map.krate; @@ -211,7 +213,7 @@ impl DefCollector { let crate_graph = &context.crate_graph[crate_id]; for dep in crate_graph.dependencies.clone() { - errors.extend(CrateDefMap::collect_defs(dep.crate_id, context)); + errors.extend(CrateDefMap::collect_defs(dep.crate_id, context, macro_processors)); let dep_def_root = context.def_map(&dep.crate_id).expect("ice: def map was just created").root; @@ -341,10 +343,9 @@ impl DefCollector { errors.extend(resolved_globals.errors); - // We run hir transformations before type checks - #[cfg(feature = "aztec")] - crate::hir::aztec_library::transform_hir(&crate_id, context); - + for macro_processor in macro_processors { + macro_processor.process_typed_ast(&crate_id, context); + } errors.extend(type_check_globals(&mut context.def_interner, resolved_globals.globals)); // Type check all of the functions in the crate diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 345e5447bf5..5f6f3f3cf2a 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -1,6 +1,7 @@ use crate::graph::CrateId; use crate::hir::def_collector::dc_crate::{CompilationError, DefCollector}; use crate::hir::Context; +use crate::macros_api::MacroProcessor; use crate::node_interner::{FuncId, NodeInterner, StructId}; use crate::parser::{parse_program, ParsedModule, ParserError}; use crate::token::{FunctionAttribute, SecondaryAttribute, TestScope}; @@ -17,6 +18,8 @@ pub use module_data::*; mod namespace; pub use namespace::*; +use super::def_collector::errors::DefCollectorErrorKind; + /// The name that is used for a non-contract program's entry-point function. pub const MAIN_FUNCTION: &str = "main"; @@ -69,6 +72,7 @@ impl CrateDefMap { pub fn collect_defs( crate_id: CrateId, context: &mut Context, + macro_processors: &[impl MacroProcessor], ) -> Vec<(CompilationError, FileId)> { // Check if this Crate has already been compiled // XXX: There is probably a better alternative for this. @@ -83,16 +87,18 @@ impl CrateDefMap { // First parse the root file. let root_file_id = context.crate_graph[crate_id].root_file_id; let (ast, parsing_errors) = parse_file(&context.file_manager, root_file_id); - let ast = ast.into_sorted(); - - #[cfg(feature = "aztec")] - let ast = match super::aztec_library::transform(ast, &crate_id, context) { - Ok(ast) => ast, - Err((error, file_id)) => { - errors.push((error.into(), file_id)); - return errors; - } - }; + let mut ast = ast.into_sorted(); + + for macro_processor in macro_processors { + ast = match macro_processor.process_untyped_ast(ast, &crate_id, context) { + Ok(ast) => ast, + Err((error, file_id)) => { + let def_error = DefCollectorErrorKind::MacroError(error); + errors.push((def_error.into(), file_id)); + return errors; + } + }; + } // Allocate a default Module for the root, giving it a ModuleId let mut modules: Arena = Arena::default(); @@ -107,7 +113,7 @@ impl CrateDefMap { }; // Now we want to populate the CrateDefMap using the DefCollector - errors.extend(DefCollector::collect(def_map, context, ast, root_file_id)); + errors.extend(DefCollector::collect(def_map, context, ast, root_file_id, macro_processors)); errors.extend( parsing_errors.iter().map(|e| (e.clone().into(), root_file_id)).collect::>(), From f2b128e796f8e708996e3b00aa1cf6cbf31ec23d Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:16:58 +0000 Subject: [PATCH 04/38] fix test --- compiler/noirc_frontend/src/tests.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 6a1cf80accd..7223718a79d 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -18,6 +18,7 @@ mod test { use crate::hir::resolution::import::PathResolutionError; use crate::hir::type_check::TypeCheckError; use crate::hir::Context; + use crate::macros_api::MacroProcessor; use crate::node_interner::{NodeInterner, StmtId}; use crate::graph::CrateGraph; @@ -54,6 +55,24 @@ mod test { .collect() } + struct DummyMacroProcessor; + + impl MacroProcessor for DummyMacroProcessor { + fn process_untyped_ast( + &self, + ast: crate::macros_api::SortedModule, + crate_id: &crate::graph::CrateId, + context: &Context, + ) -> Result + { + unimplemented!() + } + + fn process_typed_ast(&self, crate_id: &crate::graph::CrateId, context: &mut Context) { + unimplemented!() + } + } + pub(crate) fn get_program( src: &str, ) -> (ParsedModule, Context, Vec<(CompilationError, FileId)>) { @@ -85,6 +104,7 @@ mod test { &mut context, program.clone().into_sorted(), root_file_id, + &Vec::::new(), )); } (program, context, errors) From 413260c341d1533ae5d4d28fa012f4e4fadfc5fa Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:17:50 +0000 Subject: [PATCH 05/38] add aztec_macro crate --- Cargo.lock | 9 + Cargo.toml | 1 + aztec_macros/Cargo.toml | 14 + aztec_macros/src/lib.rs | 1034 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 1058 insertions(+) create mode 100644 aztec_macros/Cargo.toml create mode 100644 aztec_macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9536508436b..b4b4dcf1e27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,6 +413,14 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "aztec_macros" +version = "0.19.3" +dependencies = [ + "iter-extended", + "noirc_frontend", +] + [[package]] name = "backend-interface" version = "0.11.0" @@ -2608,6 +2616,7 @@ name = "noirc_driver" version = "0.19.3" dependencies = [ "acvm", + "aztec_macros", "build-data", "clap", "fm", diff --git a/Cargo.toml b/Cargo.toml index b891aa7d935..f7669d314d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ + "aztec_macros", "compiler/noirc_evaluator", "compiler/noirc_frontend", "compiler/noirc_errors", diff --git a/aztec_macros/Cargo.toml b/aztec_macros/Cargo.toml new file mode 100644 index 00000000000..04f74d3b022 --- /dev/null +++ b/aztec_macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "aztec_macros" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +noirc_frontend.workspace = true +iter-extended.workspace = true diff --git a/aztec_macros/src/lib.rs b/aztec_macros/src/lib.rs new file mode 100644 index 00000000000..c160b241b31 --- /dev/null +++ b/aztec_macros/src/lib.rs @@ -0,0 +1,1034 @@ +use iter_extended::vecmap; + +use noirc_frontend::macros_api::FieldElement; +use noirc_frontend::macros_api::{ + BlockExpression, CallExpression, CastExpression, Distinctness, Expression, ExpressionKind, + ForLoopStatement, ForRange, FunctionDefinition, FunctionReturnType, FunctionVisibility, + HirContext, HirExpression, HirLiteral, HirStatement, Ident, ImportStatement, IndexExpression, + LetStatement, Literal, MemberAccessExpression, MethodCallExpression, NoirFunction, NoirStruct, + Param, Path, PathKind, Pattern, PrefixExpression, SecondaryAttribute, Signedness, Span, + Statement, StatementKind, StructType, Type, TypeImpl, UnaryOp, UnresolvedType, + UnresolvedTypeData, Visibility, +}; +use noirc_frontend::macros_api::{CrateId, FileId}; +use noirc_frontend::macros_api::{MacroError, MacroProcessor}; +use noirc_frontend::macros_api::{ModuleDefId, NodeInterner, SortedModule, StructId}; + +pub struct AztecMacro; + +impl MacroProcessor for AztecMacro { + fn process_untyped_ast( + &self, + ast: SortedModule, + crate_id: &CrateId, + context: &HirContext, + ) -> Result { + transform(ast, crate_id, context) + } + + fn process_typed_ast(&self, crate_id: &CrateId, context: &mut HirContext) { + transform_hir(crate_id, context) + } +} + +#[derive(Debug, Clone)] +pub enum AztecMacroError { + // TODO(benesjan): https://github.com/AztecProtocol/aztec-packages/issues/2905 + AztecNotFound, + AztecComputeNoteHashAndNullifierNotFound { span: Span }, +} + +impl From for MacroError { + fn from(err: AztecMacroError) -> Self { + match err { + AztecMacroError::AztecNotFound {} => MacroError { + primary_message: "Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml".to_owned(), + secondary_message: None, + span: None, + }, + AztecMacroError::AztecComputeNoteHashAndNullifierNotFound { span } => MacroError { + primary_message: "compute_note_hash_and_nullifier function not found. Define it in your contract.".to_owned(), + secondary_message: None, + span: Some(span), + }, + } + } +} + +// +// Helper macros for creating noir ast nodes +// +fn ident(name: &str) -> Ident { + Ident::new(name.to_string(), Span::default()) +} + +fn ident_path(name: &str) -> Path { + Path::from_ident(ident(name)) +} + +fn path(ident: Ident) -> Path { + Path::from_ident(ident) +} + +fn expression(kind: ExpressionKind) -> Expression { + Expression::new(kind, Span::default()) +} + +fn variable(name: &str) -> Expression { + expression(ExpressionKind::Variable(ident_path(name))) +} + +fn variable_ident(identifier: Ident) -> Expression { + expression(ExpressionKind::Variable(path(identifier))) +} + +fn variable_path(path: Path) -> Expression { + expression(ExpressionKind::Variable(path)) +} + +fn method_call(object: Expression, method_name: &str, arguments: Vec) -> Expression { + expression(ExpressionKind::MethodCall(Box::new(MethodCallExpression { + object, + method_name: ident(method_name), + arguments, + }))) +} + +fn call(func: Expression, arguments: Vec) -> Expression { + expression(ExpressionKind::Call(Box::new(CallExpression { func: Box::new(func), arguments }))) +} + +fn pattern(name: &str) -> Pattern { + Pattern::Identifier(ident(name)) +} + +fn mutable(name: &str) -> Pattern { + Pattern::Mutable(Box::new(pattern(name)), Span::default()) +} + +fn mutable_assignment(name: &str, assigned_to: Expression) -> Statement { + make_statement(StatementKind::Let(LetStatement { + pattern: mutable(name), + r#type: make_type(UnresolvedTypeData::Unspecified), + expression: assigned_to, + })) +} + +fn mutable_reference(variable_name: &str) -> Expression { + expression(ExpressionKind::Prefix(Box::new(PrefixExpression { + operator: UnaryOp::MutableReference, + rhs: variable(variable_name), + }))) +} + +fn assignment(name: &str, assigned_to: Expression) -> Statement { + make_statement(StatementKind::Let(LetStatement { + pattern: pattern(name), + r#type: make_type(UnresolvedTypeData::Unspecified), + expression: assigned_to, + })) +} + +fn member_access(lhs: &str, rhs: &str) -> Expression { + expression(ExpressionKind::MemberAccess(Box::new(MemberAccessExpression { + lhs: variable(lhs), + rhs: ident(rhs), + }))) +} + +macro_rules! chained_path { + ( $base:expr $(, $tail:expr)* ) => { + { + let mut base_path = ident_path($base); + $( + base_path.segments.push(ident($tail)); + )* + base_path + } + } +} + +macro_rules! chained_dep { + ( $base:expr $(, $tail:expr)* ) => { + { + let mut base_path = ident_path($base); + base_path.kind = PathKind::Dep; + $( + base_path.segments.push(ident($tail)); + )* + base_path + } + } +} + +fn cast(lhs: Expression, ty: UnresolvedTypeData) -> Expression { + expression(ExpressionKind::Cast(Box::new(CastExpression { lhs, r#type: make_type(ty) }))) +} + +fn make_type(typ: UnresolvedTypeData) -> UnresolvedType { + UnresolvedType { typ, span: None } +} + +fn index_array(array: Ident, index: &str) -> Expression { + expression(ExpressionKind::Index(Box::new(IndexExpression { + collection: variable_path(path(array)), + index: variable(index), + }))) +} + +fn index_array_variable(array: Expression, index: &str) -> Expression { + expression(ExpressionKind::Index(Box::new(IndexExpression { + collection: array, + index: variable(index), + }))) +} + +fn import(path: Path) -> ImportStatement { + ImportStatement { path, alias: None } +} + +// +// Create AST Nodes for Aztec +// + +/// Traverses every function in the ast, calling `transform_function` which +/// determines if further processing is required +fn transform( + mut ast: SortedModule, + crate_id: &CrateId, + context: &HirContext, +) -> Result { + // Usage -> mut ast -> aztec_library::transform(&mut ast) + + // Covers all functions in the ast + for submodule in ast.submodules.iter_mut().filter(|submodule| submodule.is_contract) { + if transform_module(&mut submodule.contents, crate_id, context)? { + check_for_aztec_dependency(crate_id, context)?; + include_relevant_imports(&mut submodule.contents); + } + } + Ok(ast) +} + +// +// Transform Hir Nodes for Aztec +// + +/// Completes the Hir with data gathered from type resolution +fn transform_hir(crate_id: &CrateId, context: &mut HirContext) { + transform_events(crate_id, context); +} + +/// Includes an import to the aztec library if it has not been included yet +fn include_relevant_imports(ast: &mut SortedModule) { + // Create the aztec import path using the assumed chained_dep! macro + let aztec_import_path = import(chained_dep!("aztec")); + + // Check if the aztec import already exists + let is_aztec_imported = + ast.imports.iter().any(|existing_import| existing_import.path == aztec_import_path.path); + + // If aztec is not imported, add the import at the beginning + if !is_aztec_imported { + ast.imports.insert(0, aztec_import_path); + } +} + +/// Creates an error alerting the user that they have not downloaded the Aztec-noir library +fn check_for_aztec_dependency( + crate_id: &CrateId, + context: &HirContext, +) -> Result<(), (MacroError, FileId)> { + let crate_graph = &context.crate_graph[crate_id]; + let has_aztec_dependency = crate_graph.dependencies.iter().any(|dep| dep.as_name() == "aztec"); + if has_aztec_dependency { + Ok(()) + } else { + Err((MacroError { primary_message: "Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml".to_owned(), secondary_message: None, span: None }, crate_graph.root_file_id)) + } +} + +// Check to see if the user has defined a storage struct +fn check_for_storage_definition(module: &SortedModule) -> bool { + module.types.iter().any(|r#struct| r#struct.name.0.contents == "Storage") +} + +// Check if "compute_note_hash_and_nullifier(Field,Field,Field,[Field; N]) -> [Field; 4]" is defined +fn check_for_compute_note_hash_and_nullifier_definition(module: &SortedModule) -> bool { + module.functions.iter().any(|func| { + func.def.name.0.contents == "compute_note_hash_and_nullifier" + && func.def.parameters.len() == 4 + && func.def.parameters[0].typ.typ == UnresolvedTypeData::FieldElement + && func.def.parameters[1].typ.typ == UnresolvedTypeData::FieldElement + && func.def.parameters[2].typ.typ == UnresolvedTypeData::FieldElement + // checks if the 4th parameter is an array and the Box in + // Array(Option, Box) contains only fields + && match &func.def.parameters[3].typ.typ { + UnresolvedTypeData::Array(_, inner_type) => { + match inner_type.typ { + UnresolvedTypeData::FieldElement => true, + _ => false, + } + }, + _ => false, + } + // We check the return type the same way as we did the 4th parameter + && match &func.def.return_type { + FunctionReturnType::Default(_) => false, + FunctionReturnType::Ty(unresolved_type) => { + match &unresolved_type.typ { + UnresolvedTypeData::Array(_, inner_type) => { + match inner_type.typ { + UnresolvedTypeData::FieldElement => true, + _ => false, + } + }, + _ => false, + } + } + } + }) +} + +/// Checks if an attribute is a custom attribute with a specific name +fn is_custom_attribute(attr: &SecondaryAttribute, attribute_name: &str) -> bool { + if let SecondaryAttribute::Custom(custom_attr) = attr { + custom_attr.as_str() == attribute_name + } else { + false + } +} + +/// Determines if ast nodes are annotated with aztec attributes. +/// For annotated functions it calls the `transform` function which will perform the required transformations. +/// Returns true if an annotated node is found, false otherwise +fn transform_module( + module: &mut SortedModule, + crate_id: &CrateId, + context: &HirContext, +) -> Result { + let mut has_transformed_module = false; + + // Check for a user defined storage struct + let storage_defined = check_for_storage_definition(&module); + + if storage_defined && !check_for_compute_note_hash_and_nullifier_definition(&module) { + let crate_graph = &context.crate_graph[crate_id]; + return Err(( + MacroError { + span: Some(Span::default()), // Add a default span so we know which contract file the error originates from + primary_message: "compute_note_hash_and_nullifier function not found. Define it in your contract.".to_owned(), + secondary_message: None, + }, + crate_graph.root_file_id, + )); + } + + for structure in module.types.iter() { + if structure.attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Event)) { + module.impls.push(generate_selector_impl(structure)); + has_transformed_module = true; + } + } + + for func in module.functions.iter_mut() { + for secondary_attribute in func.def.attributes.secondary.clone() { + if is_custom_attribute(&secondary_attribute, "aztec(private)") { + transform_function("Private", func, storage_defined); + has_transformed_module = true; + } else if is_custom_attribute(&secondary_attribute, "aztec(public)") { + transform_function("Public", func, storage_defined); + has_transformed_module = true; + } + } + // Add the storage struct to the beginning of the function if it is unconstrained in an aztec contract + if storage_defined && func.def.is_unconstrained { + transform_unconstrained(func); + has_transformed_module = true; + } + } + Ok(has_transformed_module) +} + +/// If it does, it will insert the following things: +/// - A new Input that is provided for a kernel app circuit, named: {Public/Private}ContextInputs +/// - Hashes all of the function input variables +/// - This instantiates a helper function +fn transform_function(ty: &str, func: &mut NoirFunction, storage_defined: bool) { + let context_name = format!("{}Context", ty); + let inputs_name = format!("{}ContextInputs", ty); + let return_type_name = format!("{}CircuitPublicInputs", ty); + + // Add access to the storage struct + if storage_defined { + let storage_def = abstract_storage(&ty.to_lowercase(), false); + func.def.body.0.insert(0, storage_def); + } + + // Insert the context creation as the first action + let create_context = create_context(&context_name, &func.def.parameters); + func.def.body.0.splice(0..0, (create_context).iter().cloned()); + + // Add the inputs to the params + let input = create_inputs(&inputs_name); + func.def.parameters.insert(0, input); + + // Abstract return types such that they get added to the kernel's return_values + if let Some(return_values) = abstract_return_values(func) { + func.def.body.0.push(return_values); + } + + // Push the finish method call to the end of the function + let finish_def = create_context_finish(); + func.def.body.0.push(finish_def); + + let return_type = create_return_type(&return_type_name); + func.def.return_type = return_type; + func.def.return_visibility = Visibility::Public; + + // Distinct return types are only required for private functions + // Public functions should have open auto-inferred + match ty { + "Private" => func.def.return_distinctness = Distinctness::Distinct, + "Public" => func.def.is_open = true, + _ => (), + } +} + +/// Transform Unconstrained +/// +/// Inserts the following code at the beginning of an unconstrained function +/// ```noir +/// let storage = Storage::init(Context::none()); +/// ``` +/// +/// This will allow developers to access their contract' storage struct in unconstrained functions +fn transform_unconstrained(func: &mut NoirFunction) { + func.def.body.0.insert(0, abstract_storage("Unconstrained", true)); +} + +fn collect_crate_structs(crate_id: &CrateId, context: &HirContext) -> Vec { + context + .def_map(crate_id) + .expect("ICE: Missing crate in def_map") + .modules() + .iter() + .flat_map(|(_, module)| { + module.type_definitions().filter_map(|typ| { + if let ModuleDefId::TypeId(struct_id) = typ { + Some(struct_id) + } else { + None + } + }) + }) + .collect() +} + +/// Substitutes the signature literal that was introduced in the selector method previously with the actual signature. +fn transform_event(struct_id: StructId, interner: &mut NodeInterner) { + let struct_type = interner.get_struct(struct_id); + let selector_id = interner + .lookup_method(&Type::Struct(struct_type, vec![]), struct_id, "selector", false) + .expect("Selector method not found"); + let selector_function = interner.function(&selector_id); + + let compute_selector_statement = interner.statement( + selector_function + .block(interner) + .statements() + .first() + .expect("Compute selector statement not found"), + ); + + let compute_selector_expression = match compute_selector_statement { + HirStatement::Expression(expression_id) => match interner.expression(&expression_id) { + HirExpression::Call(hir_call_expression) => Some(hir_call_expression), + _ => None, + }, + _ => None, + } + .expect("Compute selector statement is not a call expression"); + + let first_arg_id = compute_selector_expression + .arguments + .first() + .expect("Missing argument for compute selector"); + + match interner.expression(first_arg_id) { + HirExpression::Literal(HirLiteral::Str(signature)) + if signature == SIGNATURE_PLACEHOLDER => + { + let selector_literal_id = first_arg_id; + + let structure = interner.get_struct(struct_id); + let signature = event_signature(&structure.borrow()); + interner.update_expression(*selector_literal_id, |expr| { + *expr = HirExpression::Literal(HirLiteral::Str(signature.clone())); + }); + + // Also update the type! It might have a different length now than the placeholder. + interner.push_expr_type( + selector_literal_id, + Type::String(Box::new(Type::Constant(signature.len() as u64))), + ); + } + _ => unreachable!("Signature placeholder literal does not match"), + } +} + +fn transform_events(crate_id: &CrateId, context: &mut HirContext) { + for struct_id in collect_crate_structs(crate_id, context) { + let attributes = context.def_interner.struct_attributes(&struct_id); + if attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Event)) { + transform_event(struct_id, &mut context.def_interner); + } + } +} + +const SIGNATURE_PLACEHOLDER: &str = "SIGNATURE_PLACEHOLDER"; + +/// Generates the impl for an event selector +/// +/// Inserts the following code: +/// ```noir +/// impl SomeStruct { +/// fn selector() -> Field { +/// aztec::oracle::compute_selector::compute_selector("SIGNATURE_PLACEHOLDER") +/// } +/// } +/// ``` +/// +/// This allows developers to emit events without having to write the signature of the event every time they emit it. +/// The signature cannot be known at this point since types are not resolved yet, so we use a signature placeholder. +/// It'll get resolved after by transforming the HIR. +fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { + let struct_type = make_type(UnresolvedTypeData::Named(path(structure.name.clone()), vec![])); + + let selector_fun_body = BlockExpression(vec![make_statement(StatementKind::Expression(call( + variable_path(chained_path!("aztec", "selector", "compute_selector")), + vec![expression(ExpressionKind::Literal(Literal::Str(SIGNATURE_PLACEHOLDER.to_string())))], + )))]); + + let mut selector_fn_def = FunctionDefinition::normal( + &ident("selector"), + &vec![], + &[], + &selector_fun_body, + &[], + &FunctionReturnType::Ty(make_type(UnresolvedTypeData::FieldElement)), + ); + + selector_fn_def.visibility = FunctionVisibility::Public; + + // Seems to be necessary on contract modules + selector_fn_def.return_visibility = Visibility::Public; + + TypeImpl { + object_type: struct_type, + type_span: structure.span, + generics: vec![], + methods: vec![NoirFunction::normal(selector_fn_def)], + } +} + +/// Helper function that returns what the private context would look like in the ast +/// This should make it available to be consumed within aztec private annotated functions. +/// +/// The replaced code: +/// ```noir +/// /// Before +/// fn foo(inputs: PrivateContextInputs) { +/// // ... +/// } +/// +/// /// After +/// #[aztec(private)] +/// fn foo() { +/// // ... +/// } +fn create_inputs(ty: &str) -> Param { + let context_ident = ident("inputs"); + let context_pattern = Pattern::Identifier(context_ident); + let type_path = chained_path!("aztec", "abi", ty); + let context_type = make_type(UnresolvedTypeData::Named(type_path, vec![])); + let visibility = Visibility::Private; + + Param { pattern: context_pattern, typ: context_type, visibility, span: Span::default() } +} + +/// Creates the private context object to be accessed within the function, the parameters need to be extracted to be +/// appended into the args hash object. +/// +/// The replaced code: +/// ```noir +/// #[aztec(private)] +/// fn foo(structInput: SomeStruct, arrayInput: [u8; 10], fieldInput: Field) -> Field { +/// // Create the hasher object +/// let mut hasher = Hasher::new(); +/// +/// // struct inputs call serialize on them to add an array of fields +/// hasher.add_multiple(structInput.serialize()); +/// +/// // Array inputs are iterated over and each element is added to the hasher (as a field) +/// for i in 0..arrayInput.len() { +/// hasher.add(arrayInput[i] as Field); +/// } +/// // Field inputs are added to the hasher +/// hasher.add({ident}); +/// +/// // Create the context +/// // The inputs (injected by this `create_inputs`) and completed hash object are passed to the context +/// let mut context = PrivateContext::new(inputs, hasher.hash()); +/// } +/// ``` +fn create_context(ty: &str, params: &[Param]) -> Vec { + let mut injected_expressions: Vec = vec![]; + + // `let mut hasher = Hasher::new();` + let let_hasher = mutable_assignment( + "hasher", // Assigned to + call( + variable_path(chained_path!("aztec", "abi", "Hasher", "new")), // Path + vec![], // args + ), + ); + + // Completes: `let mut hasher = Hasher::new();` + injected_expressions.push(let_hasher); + + // Iterate over each of the function parameters, adding to them to the hasher + params.iter().for_each(|Param { pattern, typ, span: _, visibility: _ }| { + match pattern { + Pattern::Identifier(identifier) => { + // Match the type to determine the padding to do + let unresolved_type = &typ.typ; + let expression = match unresolved_type { + // `hasher.add_multiple({ident}.serialize())` + UnresolvedTypeData::Named(..) => add_struct_to_hasher(identifier), + UnresolvedTypeData::Array(_, arr_type) => { + add_array_to_hasher(identifier, &arr_type) + } + // `hasher.add({ident})` + UnresolvedTypeData::FieldElement => add_field_to_hasher(identifier), + // Add the integer to the hasher, casted to a field + // `hasher.add({ident} as Field)` + UnresolvedTypeData::Integer(..) | UnresolvedTypeData::Bool => { + add_cast_to_hasher(identifier) + } + _ => unreachable!("[Aztec Noir] Provided parameter type is not supported"), + }; + injected_expressions.push(expression); + } + _ => todo!(), // Maybe unreachable? + } + }); + + // Create the inputs to the context + let inputs_expression = variable("inputs"); + // `hasher.hash()` + let hash_call = method_call( + variable("hasher"), // variable + "hash", // method name + vec![], // args + ); + + // let mut context = {ty}::new(inputs, hash); + let let_context = mutable_assignment( + "context", // Assigned to + call( + variable_path(chained_path!("aztec", "context", ty, "new")), // Path + vec![inputs_expression, hash_call], // args + ), + ); + injected_expressions.push(let_context); + + // Return all expressions that will be injected by the hasher + injected_expressions +} + +/// Abstract Return Type +/// +/// This function intercepts the function's current return type and replaces it with pushes +/// To the kernel +/// +/// The replaced code: +/// ```noir +/// /// Before +/// #[aztec(private)] +/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// // ... +/// let my_return_value: Field = 10; +/// context.return_values.push(my_return_value); +/// } +/// +/// /// After +/// #[aztec(private)] +/// fn foo() -> Field { +/// // ... +/// let my_return_value: Field = 10; +/// my_return_value +/// } +/// ``` +/// Similarly; Structs will be pushed to the context, after serialize() is called on them. +/// Arrays will be iterated over and each element will be pushed to the context. +/// Any primitive type that can be cast will be casted to a field and pushed to the context. +fn abstract_return_values(func: &NoirFunction) -> Option { + let current_return_type = func.return_type().typ; + let len = func.def.body.len(); + let last_statement = &func.def.body.0[len - 1]; + + // TODO: (length, type) => We can limit the size of the array returned to be limited by kernel size + // Doesn't need done until we have settled on a kernel size + // TODO: support tuples here and in inputs -> convert into an issue + + // Check if the return type is an expression, if it is, we can handle it + match last_statement { + Statement { kind: StatementKind::Expression(expression), .. } => { + match current_return_type { + // Call serialize on structs, push the whole array, calling push_array + UnresolvedTypeData::Named(..) => Some(make_struct_return_type(expression.clone())), + UnresolvedTypeData::Array(..) => Some(make_array_return_type(expression.clone())), + // Cast these types to a field before pushing + UnresolvedTypeData::Bool | UnresolvedTypeData::Integer(..) => { + Some(make_castable_return_type(expression.clone())) + } + UnresolvedTypeData::FieldElement => Some(make_return_push(expression.clone())), + _ => None, + } + } + _ => None, + } +} + +/// Abstract storage +/// +/// For private functions: +/// ```noir +/// #[aztec(private)] +/// fn lol() { +/// let storage = Storage::init(Context::private(context)); +/// } +/// ``` +/// +/// For public functions: +/// ```noir +/// #[aztec(public)] +/// fn lol() { +/// let storage = Storage::init(Context::public(context)); +/// } +/// ``` +/// +/// For unconstrained functions: +/// ```noir +/// unconstrained fn lol() { +/// let storage = Storage::init(Context::none()); +/// } +fn abstract_storage(typ: &str, unconstrained: bool) -> Statement { + let init_context_call = if unconstrained { + call( + variable_path(chained_path!("aztec", "context", "Context", "none")), // Path + vec![], // args + ) + } else { + call( + variable_path(chained_path!("aztec", "context", "Context", typ)), // Path + vec![mutable_reference("context")], // args + ) + }; + + assignment( + "storage", // Assigned to + call( + variable_path(chained_path!("Storage", "init")), // Path + vec![init_context_call], // args + ), + ) +} + +/// Context Return Values +/// +/// Creates an instance to the context return values +/// ```noir +/// `context.return_values` +/// ``` +fn context_return_values() -> Expression { + member_access("context", "return_values") +} + +fn make_statement(kind: StatementKind) -> Statement { + Statement { span: Span::default(), kind } +} + +/// Make return Push +/// +/// Translates to: +/// `context.return_values.push({push_value})` +fn make_return_push(push_value: Expression) -> Statement { + make_statement(StatementKind::Semi(method_call( + context_return_values(), + "push", + vec![push_value], + ))) +} + +/// Make Return push array +/// +/// Translates to: +/// `context.return_values.push_array({push_value})` +fn make_return_push_array(push_value: Expression) -> Statement { + make_statement(StatementKind::Semi(method_call( + context_return_values(), + "push_array", + vec![push_value], + ))) +} + +/// Make struct return type +/// +/// Translates to: +/// ```noir +/// `context.return_values.push_array({push_value}.serialize())` +fn make_struct_return_type(expression: Expression) -> Statement { + let serialized_call = method_call( + expression, // variable + "serialize", // method name + vec![], // args + ); + make_return_push_array(serialized_call) +} + +/// Make array return type +/// +/// Translates to: +/// ```noir +/// for i in 0..{ident}.len() { +/// context.return_values.push({ident}[i] as Field) +/// } +/// ``` +fn make_array_return_type(expression: Expression) -> Statement { + let inner_cast_expression = + cast(index_array_variable(expression.clone(), "i"), UnresolvedTypeData::FieldElement); + let assignment = make_statement(StatementKind::Semi(method_call( + context_return_values(), // variable + "push", // method name + vec![inner_cast_expression], + ))); + + create_loop_over(expression, vec![assignment]) +} + +/// Castable return type +/// +/// Translates to: +/// ```noir +/// context.return_values.push({ident} as Field) +/// ``` +fn make_castable_return_type(expression: Expression) -> Statement { + // Cast these types to a field before pushing + let cast_expression = cast(expression, UnresolvedTypeData::FieldElement); + make_return_push(cast_expression) +} + +/// Create Return Type +/// +/// Public functions return abi::PublicCircuitPublicInputs while +/// private functions return abi::PrivateCircuitPublicInputs +/// +/// This call constructs an ast token referencing the above types +/// The name is set in the function above `transform`, hence the +/// whole token name is passed in +/// +/// The replaced code: +/// ```noir +/// +/// /// Before +/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// // ... +/// } +/// +/// /// After +/// #[aztec(private)] +/// fn foo() { +/// // ... +/// } +fn create_return_type(ty: &str) -> FunctionReturnType { + let return_path = chained_path!("aztec", "abi", ty); + + let ty = make_type(UnresolvedTypeData::Named(return_path, vec![])); + FunctionReturnType::Ty(ty) +} + +/// Create Context Finish +/// +/// Each aztec function calls `context.finish()` at the end of a function +/// to return values required by the kernel. +/// +/// The replaced code: +/// ```noir +/// /// Before +/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// // ... +/// context.finish() +/// } +/// +/// /// After +/// #[aztec(private)] +/// fn foo() { +/// // ... +/// } +fn create_context_finish() -> Statement { + let method_call = method_call( + variable("context"), // variable + "finish", // method name + vec![], // args + ); + make_statement(StatementKind::Expression(method_call)) +} + +// +// Methods to create hasher inputs +// + +fn add_struct_to_hasher(identifier: &Ident) -> Statement { + // If this is a struct, we call serialize and add the array to the hasher + let serialized_call = method_call( + variable_path(path(identifier.clone())), // variable + "serialize", // method name + vec![], // args + ); + + make_statement(StatementKind::Semi(method_call( + variable("hasher"), // variable + "add_multiple", // method name + vec![serialized_call], // args + ))) +} + +fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { + // If this is an array of primitive types (integers / fields) we can add them each to the hasher + // casted to a field + let span = var.span.clone(); + + // `array.len()` + let end_range_expression = method_call( + var, // variable + "len", // method name + vec![], // args + ); + + // What will be looped over + // - `hasher.add({ident}[i] as Field)` + let for_loop_block = expression(ExpressionKind::Block(BlockExpression(loop_body))); + + // `for i in 0..{ident}.len()` + make_statement(StatementKind::For(ForLoopStatement { + range: ForRange::Range( + expression(ExpressionKind::Literal(Literal::Integer(FieldElement::from(i128::from( + 0, + ))))), + end_range_expression, + ), + identifier: ident("i"), + block: for_loop_block, + span, + })) +} + +fn add_array_to_hasher(identifier: &Ident, arr_type: &UnresolvedType) -> Statement { + // If this is an array of primitive types (integers / fields) we can add them each to the hasher + // casted to a field + + // Wrap in the semi thing - does that mean ended with semi colon? + // `hasher.add({ident}[i] as Field)` + + let arr_index = index_array(identifier.clone(), "i"); + let (add_expression, hasher_method_name) = match arr_type.typ { + UnresolvedTypeData::Named(..) => { + let hasher_method_name = "add_multiple".to_owned(); + let call = method_call( + // All serialise on each element + arr_index, // variable + "serialize", // method name + vec![], // args + ); + (call, hasher_method_name) + } + _ => { + let hasher_method_name = "add".to_owned(); + let call = cast( + arr_index, // lhs - `ident[i]` + UnresolvedTypeData::FieldElement, // cast to - `as Field` + ); + (call, hasher_method_name) + } + }; + + let block_statement = make_statement(StatementKind::Semi(method_call( + variable("hasher"), // variable + &hasher_method_name, // method name + vec![add_expression], + ))); + + create_loop_over(variable_ident(identifier.clone()), vec![block_statement]) +} + +fn add_field_to_hasher(identifier: &Ident) -> Statement { + // `hasher.add({ident})` + let ident = variable_path(path(identifier.clone())); + make_statement(StatementKind::Semi(method_call( + variable("hasher"), // variable + "add", // method name + vec![ident], // args + ))) +} + +fn add_cast_to_hasher(identifier: &Ident) -> Statement { + // `hasher.add({ident} as Field)` + // `{ident} as Field` + let cast_operation = cast( + variable_path(path(identifier.clone())), // lhs + UnresolvedTypeData::FieldElement, // rhs + ); + + // `hasher.add({ident} as Field)` + make_statement(StatementKind::Semi(method_call( + variable("hasher"), // variable + "add", // method name + vec![cast_operation], // args + ))) +} + +/// Computes the aztec signature for a resolved type. +fn signature_of_type(typ: &Type) -> String { + match typ { + Type::Integer(Signedness::Signed, bit_size) => format!("i{}", bit_size), + Type::Integer(Signedness::Unsigned, bit_size) => format!("u{}", bit_size), + Type::FieldElement => "Field".to_owned(), + Type::Bool => "bool".to_owned(), + Type::Array(len, typ) => { + if let Type::Constant(len) = **len { + format!("[{};{len}]", signature_of_type(typ)) + } else { + unimplemented!("Cannot generate signature for array with length type {:?}", typ) + } + } + Type::Struct(def, args) => { + let fields = def.borrow().get_fields(args); + let fields = vecmap(fields, |(_, typ)| signature_of_type(&typ)); + format!("({})", fields.join(",")) + } + Type::Tuple(types) => { + let fields = vecmap(types, signature_of_type); + format!("({})", fields.join(",")) + } + _ => unimplemented!("Cannot generate signature for type {:?}", typ), + } +} + +/// Computes the signature for a resolved event type. +/// It has the form 'EventName(Field,(Field),[u8;2])' +fn event_signature(event: &StructType) -> String { + let fields = vecmap(event.get_fields(&[]), |(_, typ)| signature_of_type(&typ)); + format!("{}({})", event.name.0.contents, fields.join(",")) +} From 8282ffe72314f10230c96171c8adaca7aabb65d8 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:18:18 +0000 Subject: [PATCH 06/38] remove aztec feature flag and code from noirc_frontend --- compiler/noirc_frontend/Cargo.toml | 3 - .../noirc_frontend/src/hir/aztec_library.rs | 1001 ----------------- compiler/noirc_frontend/src/hir/mod.rs | 3 - 3 files changed, 1007 deletions(-) delete mode 100644 compiler/noirc_frontend/src/hir/aztec_library.rs diff --git a/compiler/noirc_frontend/Cargo.toml b/compiler/noirc_frontend/Cargo.toml index 246d6617c94..6f3c35a814a 100644 --- a/compiler/noirc_frontend/Cargo.toml +++ b/compiler/noirc_frontend/Cargo.toml @@ -26,6 +26,3 @@ regex = "1.9.1" [dev-dependencies] strum = "0.24" strum_macros = "0.24" - -[features] -aztec = [] diff --git a/compiler/noirc_frontend/src/hir/aztec_library.rs b/compiler/noirc_frontend/src/hir/aztec_library.rs deleted file mode 100644 index 3b4703dc60f..00000000000 --- a/compiler/noirc_frontend/src/hir/aztec_library.rs +++ /dev/null @@ -1,1001 +0,0 @@ -use acvm::FieldElement; -use iter_extended::vecmap; -use noirc_errors::Span; - -use crate::graph::CrateId; -use crate::hir::def_collector::errors::DefCollectorErrorKind; -use crate::hir_def::expr::{HirExpression, HirLiteral}; -use crate::hir_def::stmt::HirStatement; -use crate::node_interner::{NodeInterner, StructId}; -use crate::parser::SortedModule; -use crate::token::SecondaryAttribute; -use crate::{ - hir::Context, BlockExpression, CallExpression, CastExpression, Distinctness, Expression, - ExpressionKind, FunctionReturnType, Ident, IndexExpression, LetStatement, Literal, - MemberAccessExpression, MethodCallExpression, NoirFunction, Path, PathKind, Pattern, Statement, - UnresolvedType, UnresolvedTypeData, Visibility, -}; -use crate::{ - ForLoopStatement, ForRange, FunctionDefinition, FunctionVisibility, ImportStatement, - NoirStruct, Param, PrefixExpression, Signedness, StatementKind, StructType, Type, TypeImpl, - UnaryOp, -}; -use fm::FileId; - -use super::def_map::ModuleDefId; - -// -// Helper macros for creating noir ast nodes -// -fn ident(name: &str) -> Ident { - Ident::new(name.to_string(), Span::default()) -} - -fn ident_path(name: &str) -> Path { - Path::from_ident(ident(name)) -} - -fn path(ident: Ident) -> Path { - Path::from_ident(ident) -} - -fn expression(kind: ExpressionKind) -> Expression { - Expression::new(kind, Span::default()) -} - -fn variable(name: &str) -> Expression { - expression(ExpressionKind::Variable(ident_path(name))) -} - -fn variable_ident(identifier: Ident) -> Expression { - expression(ExpressionKind::Variable(path(identifier))) -} - -fn variable_path(path: Path) -> Expression { - expression(ExpressionKind::Variable(path)) -} - -fn method_call(object: Expression, method_name: &str, arguments: Vec) -> Expression { - expression(ExpressionKind::MethodCall(Box::new(MethodCallExpression { - object, - method_name: ident(method_name), - arguments, - }))) -} - -fn call(func: Expression, arguments: Vec) -> Expression { - expression(ExpressionKind::Call(Box::new(CallExpression { func: Box::new(func), arguments }))) -} - -fn pattern(name: &str) -> Pattern { - Pattern::Identifier(ident(name)) -} - -fn mutable(name: &str) -> Pattern { - Pattern::Mutable(Box::new(pattern(name)), Span::default()) -} - -fn mutable_assignment(name: &str, assigned_to: Expression) -> Statement { - make_statement(StatementKind::Let(LetStatement { - pattern: mutable(name), - r#type: make_type(UnresolvedTypeData::Unspecified), - expression: assigned_to, - })) -} - -fn mutable_reference(variable_name: &str) -> Expression { - expression(ExpressionKind::Prefix(Box::new(PrefixExpression { - operator: UnaryOp::MutableReference, - rhs: variable(variable_name), - }))) -} - -fn assignment(name: &str, assigned_to: Expression) -> Statement { - make_statement(StatementKind::Let(LetStatement { - pattern: pattern(name), - r#type: make_type(UnresolvedTypeData::Unspecified), - expression: assigned_to, - })) -} - -fn member_access(lhs: &str, rhs: &str) -> Expression { - expression(ExpressionKind::MemberAccess(Box::new(MemberAccessExpression { - lhs: variable(lhs), - rhs: ident(rhs), - }))) -} - -macro_rules! chained_path { - ( $base:expr $(, $tail:expr)* ) => { - { - let mut base_path = ident_path($base); - $( - base_path.segments.push(ident($tail)); - )* - base_path - } - } -} - -macro_rules! chained_dep { - ( $base:expr $(, $tail:expr)* ) => { - { - let mut base_path = ident_path($base); - base_path.kind = PathKind::Dep; - $( - base_path.segments.push(ident($tail)); - )* - base_path - } - } -} - -fn cast(lhs: Expression, ty: UnresolvedTypeData) -> Expression { - expression(ExpressionKind::Cast(Box::new(CastExpression { lhs, r#type: make_type(ty) }))) -} - -fn make_type(typ: UnresolvedTypeData) -> UnresolvedType { - UnresolvedType { typ, span: None } -} - -fn index_array(array: Ident, index: &str) -> Expression { - expression(ExpressionKind::Index(Box::new(IndexExpression { - collection: variable_path(path(array)), - index: variable(index), - }))) -} - -fn index_array_variable(array: Expression, index: &str) -> Expression { - expression(ExpressionKind::Index(Box::new(IndexExpression { - collection: array, - index: variable(index), - }))) -} - -fn import(path: Path) -> ImportStatement { - ImportStatement { path, alias: None } -} - -// -// Create AST Nodes for Aztec -// - -/// Traverses every function in the ast, calling `transform_function` which -/// determines if further processing is required -pub(crate) fn transform( - mut ast: SortedModule, - crate_id: &CrateId, - context: &Context, -) -> Result { - // Usage -> mut ast -> aztec_library::transform(&mut ast) - - // Covers all functions in the ast - for submodule in ast.submodules.iter_mut().filter(|submodule| submodule.is_contract) { - if transform_module(&mut submodule.contents, crate_id, context)? { - check_for_aztec_dependency(crate_id, context)?; - include_relevant_imports(&mut submodule.contents); - } - } - Ok(ast) -} - -// -// Transform Hir Nodes for Aztec -// - -/// Completes the Hir with data gathered from type resolution -pub(crate) fn transform_hir(crate_id: &CrateId, context: &mut Context) { - transform_events(crate_id, context); -} - -/// Includes an import to the aztec library if it has not been included yet -fn include_relevant_imports(ast: &mut SortedModule) { - // Create the aztec import path using the assumed chained_dep! macro - let aztec_import_path = import(chained_dep!("aztec")); - - // Check if the aztec import already exists - let is_aztec_imported = - ast.imports.iter().any(|existing_import| existing_import.path == aztec_import_path.path); - - // If aztec is not imported, add the import at the beginning - if !is_aztec_imported { - ast.imports.insert(0, aztec_import_path); - } -} - -/// Creates an error alerting the user that they have not downloaded the Aztec-noir library -fn check_for_aztec_dependency( - crate_id: &CrateId, - context: &Context, -) -> Result<(), (DefCollectorErrorKind, FileId)> { - let crate_graph = &context.crate_graph[crate_id]; - let has_aztec_dependency = crate_graph.dependencies.iter().any(|dep| dep.as_name() == "aztec"); - if has_aztec_dependency { - Ok(()) - } else { - Err((DefCollectorErrorKind::AztecNotFound {}, crate_graph.root_file_id)) - } -} - -// Check to see if the user has defined a storage struct -fn check_for_storage_definition(module: &SortedModule) -> bool { - module.types.iter().any(|r#struct| r#struct.name.0.contents == "Storage") -} - -// Check if "compute_note_hash_and_nullifier(Field,Field,Field,[Field; N]) -> [Field; 4]" is defined -fn check_for_compute_note_hash_and_nullifier_definition(module: &SortedModule) -> bool { - module.functions.iter().any(|func| { - func.def.name.0.contents == "compute_note_hash_and_nullifier" - && func.def.parameters.len() == 4 - && func.def.parameters[0].typ.typ == UnresolvedTypeData::FieldElement - && func.def.parameters[1].typ.typ == UnresolvedTypeData::FieldElement - && func.def.parameters[2].typ.typ == UnresolvedTypeData::FieldElement - // checks if the 4th parameter is an array and the Box in - // Array(Option, Box) contains only fields - && match &func.def.parameters[3].typ.typ { - UnresolvedTypeData::Array(_, inner_type) => { - match inner_type.typ { - UnresolvedTypeData::FieldElement => true, - _ => false, - } - }, - _ => false, - } - // We check the return type the same way as we did the 4th parameter - && match &func.def.return_type { - FunctionReturnType::Default(_) => false, - FunctionReturnType::Ty(unresolved_type) => { - match &unresolved_type.typ { - UnresolvedTypeData::Array(_, inner_type) => { - match inner_type.typ { - UnresolvedTypeData::FieldElement => true, - _ => false, - } - }, - _ => false, - } - } - } - }) -} - -/// Checks if an attribute is a custom attribute with a specific name -fn is_custom_attribute(attr: &SecondaryAttribute, attribute_name: &str) -> bool { - if let SecondaryAttribute::Custom(custom_attr) = attr { - custom_attr.as_str() == attribute_name - } else { - false - } -} - -/// Determines if ast nodes are annotated with aztec attributes. -/// For annotated functions it calls the `transform` function which will perform the required transformations. -/// Returns true if an annotated node is found, false otherwise -fn transform_module( - module: &mut SortedModule, - crate_id: &CrateId, - context: &Context, -) -> Result { - let mut has_transformed_module = false; - - // Check for a user defined storage struct - let storage_defined = check_for_storage_definition(&module); - - if storage_defined && !check_for_compute_note_hash_and_nullifier_definition(&module) { - let crate_graph = &context.crate_graph[crate_id]; - return Err(( - DefCollectorErrorKind::AztecComputeNoteHashAndNullifierNotFound { - span: Span::default(), // Add a default span so we know which contract file the error originates from - }, - crate_graph.root_file_id, - )); - } - - for structure in module.types.iter() { - if structure.attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Event)) { - module.impls.push(generate_selector_impl(structure)); - has_transformed_module = true; - } - } - - for func in module.functions.iter_mut() { - for secondary_attribute in func.def.attributes.secondary.clone() { - if is_custom_attribute(&secondary_attribute, "aztec(private)") { - transform_function("Private", func, storage_defined); - has_transformed_module = true; - } else if is_custom_attribute(&secondary_attribute, "aztec(public)") { - transform_function("Public", func, storage_defined); - has_transformed_module = true; - } - } - // Add the storage struct to the beginning of the function if it is unconstrained in an aztec contract - if storage_defined && func.def.is_unconstrained { - transform_unconstrained(func); - has_transformed_module = true; - } - } - Ok(has_transformed_module) -} - -/// If it does, it will insert the following things: -/// - A new Input that is provided for a kernel app circuit, named: {Public/Private}ContextInputs -/// - Hashes all of the function input variables -/// - This instantiates a helper function -fn transform_function(ty: &str, func: &mut NoirFunction, storage_defined: bool) { - let context_name = format!("{}Context", ty); - let inputs_name = format!("{}ContextInputs", ty); - let return_type_name = format!("{}CircuitPublicInputs", ty); - - // Add access to the storage struct - if storage_defined { - let storage_def = abstract_storage(&ty.to_lowercase(), false); - func.def.body.0.insert(0, storage_def); - } - - // Insert the context creation as the first action - let create_context = create_context(&context_name, &func.def.parameters); - func.def.body.0.splice(0..0, (create_context).iter().cloned()); - - // Add the inputs to the params - let input = create_inputs(&inputs_name); - func.def.parameters.insert(0, input); - - // Abstract return types such that they get added to the kernel's return_values - if let Some(return_values) = abstract_return_values(func) { - func.def.body.0.push(return_values); - } - - // Push the finish method call to the end of the function - let finish_def = create_context_finish(); - func.def.body.0.push(finish_def); - - let return_type = create_return_type(&return_type_name); - func.def.return_type = return_type; - func.def.return_visibility = Visibility::Public; - - // Distinct return types are only required for private functions - // Public functions should have open auto-inferred - match ty { - "Private" => func.def.return_distinctness = Distinctness::Distinct, - "Public" => func.def.is_open = true, - _ => (), - } -} - -/// Transform Unconstrained -/// -/// Inserts the following code at the beginning of an unconstrained function -/// ```noir -/// let storage = Storage::init(Context::none()); -/// ``` -/// -/// This will allow developers to access their contract' storage struct in unconstrained functions -fn transform_unconstrained(func: &mut NoirFunction) { - func.def.body.0.insert(0, abstract_storage("Unconstrained", true)); -} - -fn collect_crate_structs(crate_id: &CrateId, context: &Context) -> Vec { - context - .def_map(crate_id) - .expect("ICE: Missing crate in def_map") - .modules() - .iter() - .flat_map(|(_, module)| { - module.type_definitions().filter_map(|typ| { - if let ModuleDefId::TypeId(struct_id) = typ { - Some(struct_id) - } else { - None - } - }) - }) - .collect() -} - -/// Substitutes the signature literal that was introduced in the selector method previously with the actual signature. -fn transform_event(struct_id: StructId, interner: &mut NodeInterner) { - let struct_type = interner.get_struct(struct_id); - let selector_id = interner - .lookup_method(&Type::Struct(struct_type, vec![]), struct_id, "selector", false) - .expect("Selector method not found"); - let selector_function = interner.function(&selector_id); - - let compute_selector_statement = interner.statement( - selector_function - .block(interner) - .statements() - .first() - .expect("Compute selector statement not found"), - ); - - let compute_selector_expression = match compute_selector_statement { - HirStatement::Expression(expression_id) => match interner.expression(&expression_id) { - HirExpression::Call(hir_call_expression) => Some(hir_call_expression), - _ => None, - }, - _ => None, - } - .expect("Compute selector statement is not a call expression"); - - let first_arg_id = compute_selector_expression - .arguments - .first() - .expect("Missing argument for compute selector"); - - match interner.expression(first_arg_id) { - HirExpression::Literal(HirLiteral::Str(signature)) - if signature == SIGNATURE_PLACEHOLDER => - { - let selector_literal_id = first_arg_id; - - let structure = interner.get_struct(struct_id); - let signature = event_signature(&structure.borrow()); - interner.update_expression(*selector_literal_id, |expr| { - *expr = HirExpression::Literal(HirLiteral::Str(signature.clone())); - }); - - // Also update the type! It might have a different length now than the placeholder. - interner.push_expr_type( - selector_literal_id, - Type::String(Box::new(Type::Constant(signature.len() as u64))), - ); - } - _ => unreachable!("Signature placeholder literal does not match"), - } -} - -fn transform_events(crate_id: &CrateId, context: &mut Context) { - for struct_id in collect_crate_structs(crate_id, context) { - let attributes = context.def_interner.struct_attributes(&struct_id); - if attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Event)) { - transform_event(struct_id, &mut context.def_interner); - } - } -} - -const SIGNATURE_PLACEHOLDER: &str = "SIGNATURE_PLACEHOLDER"; - -/// Generates the impl for an event selector -/// -/// Inserts the following code: -/// ```noir -/// impl SomeStruct { -/// fn selector() -> Field { -/// aztec::oracle::compute_selector::compute_selector("SIGNATURE_PLACEHOLDER") -/// } -/// } -/// ``` -/// -/// This allows developers to emit events without having to write the signature of the event every time they emit it. -/// The signature cannot be known at this point since types are not resolved yet, so we use a signature placeholder. -/// It'll get resolved after by transforming the HIR. -fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { - let struct_type = make_type(UnresolvedTypeData::Named(path(structure.name.clone()), vec![])); - - let selector_fun_body = BlockExpression(vec![make_statement(StatementKind::Expression(call( - variable_path(chained_path!("aztec", "selector", "compute_selector")), - vec![expression(ExpressionKind::Literal(Literal::Str(SIGNATURE_PLACEHOLDER.to_string())))], - )))]); - - let mut selector_fn_def = FunctionDefinition::normal( - &ident("selector"), - &vec![], - &[], - &selector_fun_body, - &[], - &FunctionReturnType::Ty(make_type(UnresolvedTypeData::FieldElement)), - ); - - selector_fn_def.visibility = FunctionVisibility::Public; - - // Seems to be necessary on contract modules - selector_fn_def.return_visibility = Visibility::Public; - - TypeImpl { - object_type: struct_type, - type_span: structure.span, - generics: vec![], - methods: vec![NoirFunction::normal(selector_fn_def)], - } -} - -/// Helper function that returns what the private context would look like in the ast -/// This should make it available to be consumed within aztec private annotated functions. -/// -/// The replaced code: -/// ```noir -/// /// Before -/// fn foo(inputs: PrivateContextInputs) { -/// // ... -/// } -/// -/// /// After -/// #[aztec(private)] -/// fn foo() { -/// // ... -/// } -pub(crate) fn create_inputs(ty: &str) -> Param { - let context_ident = ident("inputs"); - let context_pattern = Pattern::Identifier(context_ident); - let type_path = chained_path!("aztec", "abi", ty); - let context_type = make_type(UnresolvedTypeData::Named(type_path, vec![])); - let visibility = Visibility::Private; - - Param { pattern: context_pattern, typ: context_type, visibility, span: Span::default() } -} - -/// Creates the private context object to be accessed within the function, the parameters need to be extracted to be -/// appended into the args hash object. -/// -/// The replaced code: -/// ```noir -/// #[aztec(private)] -/// fn foo(structInput: SomeStruct, arrayInput: [u8; 10], fieldInput: Field) -> Field { -/// // Create the hasher object -/// let mut hasher = Hasher::new(); -/// -/// // struct inputs call serialize on them to add an array of fields -/// hasher.add_multiple(structInput.serialize()); -/// -/// // Array inputs are iterated over and each element is added to the hasher (as a field) -/// for i in 0..arrayInput.len() { -/// hasher.add(arrayInput[i] as Field); -/// } -/// // Field inputs are added to the hasher -/// hasher.add({ident}); -/// -/// // Create the context -/// // The inputs (injected by this `create_inputs`) and completed hash object are passed to the context -/// let mut context = PrivateContext::new(inputs, hasher.hash()); -/// } -/// ``` -fn create_context(ty: &str, params: &[Param]) -> Vec { - let mut injected_expressions: Vec = vec![]; - - // `let mut hasher = Hasher::new();` - let let_hasher = mutable_assignment( - "hasher", // Assigned to - call( - variable_path(chained_path!("aztec", "abi", "Hasher", "new")), // Path - vec![], // args - ), - ); - - // Completes: `let mut hasher = Hasher::new();` - injected_expressions.push(let_hasher); - - // Iterate over each of the function parameters, adding to them to the hasher - params.iter().for_each(|Param { pattern, typ, span: _, visibility: _ }| { - match pattern { - Pattern::Identifier(identifier) => { - // Match the type to determine the padding to do - let unresolved_type = &typ.typ; - let expression = match unresolved_type { - // `hasher.add_multiple({ident}.serialize())` - UnresolvedTypeData::Named(..) => add_struct_to_hasher(identifier), - UnresolvedTypeData::Array(_, arr_type) => { - add_array_to_hasher(identifier, &arr_type) - } - // `hasher.add({ident})` - UnresolvedTypeData::FieldElement => add_field_to_hasher(identifier), - // Add the integer to the hasher, casted to a field - // `hasher.add({ident} as Field)` - UnresolvedTypeData::Integer(..) | UnresolvedTypeData::Bool => { - add_cast_to_hasher(identifier) - } - _ => unreachable!("[Aztec Noir] Provided parameter type is not supported"), - }; - injected_expressions.push(expression); - } - _ => todo!(), // Maybe unreachable? - } - }); - - // Create the inputs to the context - let inputs_expression = variable("inputs"); - // `hasher.hash()` - let hash_call = method_call( - variable("hasher"), // variable - "hash", // method name - vec![], // args - ); - - // let mut context = {ty}::new(inputs, hash); - let let_context = mutable_assignment( - "context", // Assigned to - call( - variable_path(chained_path!("aztec", "context", ty, "new")), // Path - vec![inputs_expression, hash_call], // args - ), - ); - injected_expressions.push(let_context); - - // Return all expressions that will be injected by the hasher - injected_expressions -} - -/// Abstract Return Type -/// -/// This function intercepts the function's current return type and replaces it with pushes -/// To the kernel -/// -/// The replaced code: -/// ```noir -/// /// Before -/// #[aztec(private)] -/// fn foo() -> abi::PrivateCircuitPublicInputs { -/// // ... -/// let my_return_value: Field = 10; -/// context.return_values.push(my_return_value); -/// } -/// -/// /// After -/// #[aztec(private)] -/// fn foo() -> Field { -/// // ... -/// let my_return_value: Field = 10; -/// my_return_value -/// } -/// ``` -/// Similarly; Structs will be pushed to the context, after serialize() is called on them. -/// Arrays will be iterated over and each element will be pushed to the context. -/// Any primitive type that can be cast will be casted to a field and pushed to the context. -fn abstract_return_values(func: &NoirFunction) -> Option { - let current_return_type = func.return_type().typ; - let len = func.def.body.len(); - let last_statement = &func.def.body.0[len - 1]; - - // TODO: (length, type) => We can limit the size of the array returned to be limited by kernel size - // Doesn't need done until we have settled on a kernel size - // TODO: support tuples here and in inputs -> convert into an issue - - // Check if the return type is an expression, if it is, we can handle it - match last_statement { - Statement { kind: StatementKind::Expression(expression), .. } => { - match current_return_type { - // Call serialize on structs, push the whole array, calling push_array - UnresolvedTypeData::Named(..) => Some(make_struct_return_type(expression.clone())), - UnresolvedTypeData::Array(..) => Some(make_array_return_type(expression.clone())), - // Cast these types to a field before pushing - UnresolvedTypeData::Bool | UnresolvedTypeData::Integer(..) => { - Some(make_castable_return_type(expression.clone())) - } - UnresolvedTypeData::FieldElement => Some(make_return_push(expression.clone())), - _ => None, - } - } - _ => None, - } -} - -/// Abstract storage -/// -/// For private functions: -/// ```noir -/// #[aztec(private)] -/// fn lol() { -/// let storage = Storage::init(Context::private(context)); -/// } -/// ``` -/// -/// For public functions: -/// ```noir -/// #[aztec(public)] -/// fn lol() { -/// let storage = Storage::init(Context::public(context)); -/// } -/// ``` -/// -/// For unconstrained functions: -/// ```noir -/// unconstrained fn lol() { -/// let storage = Storage::init(Context::none()); -/// } -fn abstract_storage(typ: &str, unconstrained: bool) -> Statement { - let init_context_call = if unconstrained { - call( - variable_path(chained_path!("aztec", "context", "Context", "none")), // Path - vec![], // args - ) - } else { - call( - variable_path(chained_path!("aztec", "context", "Context", typ)), // Path - vec![mutable_reference("context")], // args - ) - }; - - assignment( - "storage", // Assigned to - call( - variable_path(chained_path!("Storage", "init")), // Path - vec![init_context_call], // args - ), - ) -} - -/// Context Return Values -/// -/// Creates an instance to the context return values -/// ```noir -/// `context.return_values` -/// ``` -fn context_return_values() -> Expression { - member_access("context", "return_values") -} - -fn make_statement(kind: StatementKind) -> Statement { - Statement { span: Span::default(), kind } -} - -/// Make return Push -/// -/// Translates to: -/// `context.return_values.push({push_value})` -fn make_return_push(push_value: Expression) -> Statement { - make_statement(StatementKind::Semi(method_call( - context_return_values(), - "push", - vec![push_value], - ))) -} - -/// Make Return push array -/// -/// Translates to: -/// `context.return_values.push_array({push_value})` -fn make_return_push_array(push_value: Expression) -> Statement { - make_statement(StatementKind::Semi(method_call( - context_return_values(), - "push_array", - vec![push_value], - ))) -} - -/// Make struct return type -/// -/// Translates to: -/// ```noir -/// `context.return_values.push_array({push_value}.serialize())` -fn make_struct_return_type(expression: Expression) -> Statement { - let serialized_call = method_call( - expression, // variable - "serialize", // method name - vec![], // args - ); - make_return_push_array(serialized_call) -} - -/// Make array return type -/// -/// Translates to: -/// ```noir -/// for i in 0..{ident}.len() { -/// context.return_values.push({ident}[i] as Field) -/// } -/// ``` -fn make_array_return_type(expression: Expression) -> Statement { - let inner_cast_expression = - cast(index_array_variable(expression.clone(), "i"), UnresolvedTypeData::FieldElement); - let assignment = make_statement(StatementKind::Semi(method_call( - context_return_values(), // variable - "push", // method name - vec![inner_cast_expression], - ))); - - create_loop_over(expression, vec![assignment]) -} - -/// Castable return type -/// -/// Translates to: -/// ```noir -/// context.return_values.push({ident} as Field) -/// ``` -fn make_castable_return_type(expression: Expression) -> Statement { - // Cast these types to a field before pushing - let cast_expression = cast(expression, UnresolvedTypeData::FieldElement); - make_return_push(cast_expression) -} - -/// Create Return Type -/// -/// Public functions return abi::PublicCircuitPublicInputs while -/// private functions return abi::PrivateCircuitPublicInputs -/// -/// This call constructs an ast token referencing the above types -/// The name is set in the function above `transform`, hence the -/// whole token name is passed in -/// -/// The replaced code: -/// ```noir -/// -/// /// Before -/// fn foo() -> abi::PrivateCircuitPublicInputs { -/// // ... -/// } -/// -/// /// After -/// #[aztec(private)] -/// fn foo() { -/// // ... -/// } -pub(crate) fn create_return_type(ty: &str) -> FunctionReturnType { - let return_path = chained_path!("aztec", "abi", ty); - - let ty = make_type(UnresolvedTypeData::Named(return_path, vec![])); - FunctionReturnType::Ty(ty) -} - -/// Create Context Finish -/// -/// Each aztec function calls `context.finish()` at the end of a function -/// to return values required by the kernel. -/// -/// The replaced code: -/// ```noir -/// /// Before -/// fn foo() -> abi::PrivateCircuitPublicInputs { -/// // ... -/// context.finish() -/// } -/// -/// /// After -/// #[aztec(private)] -/// fn foo() { -/// // ... -/// } -pub(crate) fn create_context_finish() -> Statement { - let method_call = method_call( - variable("context"), // variable - "finish", // method name - vec![], // args - ); - make_statement(StatementKind::Expression(method_call)) -} - -// -// Methods to create hasher inputs -// - -fn add_struct_to_hasher(identifier: &Ident) -> Statement { - // If this is a struct, we call serialize and add the array to the hasher - let serialized_call = method_call( - variable_path(path(identifier.clone())), // variable - "serialize", // method name - vec![], // args - ); - - make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add_multiple", // method name - vec![serialized_call], // args - ))) -} - -fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { - // If this is an array of primitive types (integers / fields) we can add them each to the hasher - // casted to a field - let span = var.span.clone(); - - // `array.len()` - let end_range_expression = method_call( - var, // variable - "len", // method name - vec![], // args - ); - - // What will be looped over - // - `hasher.add({ident}[i] as Field)` - let for_loop_block = expression(ExpressionKind::Block(BlockExpression(loop_body))); - - // `for i in 0..{ident}.len()` - make_statement(StatementKind::For(ForLoopStatement { - range: ForRange::Range( - expression(ExpressionKind::Literal(Literal::Integer(FieldElement::from(i128::from( - 0, - ))))), - end_range_expression, - ), - identifier: ident("i"), - block: for_loop_block, - span, - })) -} - -fn add_array_to_hasher(identifier: &Ident, arr_type: &UnresolvedType) -> Statement { - // If this is an array of primitive types (integers / fields) we can add them each to the hasher - // casted to a field - - // Wrap in the semi thing - does that mean ended with semi colon? - // `hasher.add({ident}[i] as Field)` - - let arr_index = index_array(identifier.clone(), "i"); - let (add_expression, hasher_method_name) = match arr_type.typ { - UnresolvedTypeData::Named(..) => { - let hasher_method_name = "add_multiple".to_owned(); - let call = method_call( - // All serialise on each element - arr_index, // variable - "serialize", // method name - vec![], // args - ); - (call, hasher_method_name) - } - _ => { - let hasher_method_name = "add".to_owned(); - let call = cast( - arr_index, // lhs - `ident[i]` - UnresolvedTypeData::FieldElement, // cast to - `as Field` - ); - (call, hasher_method_name) - } - }; - - let block_statement = make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - &hasher_method_name, // method name - vec![add_expression], - ))); - - create_loop_over(variable_ident(identifier.clone()), vec![block_statement]) -} - -fn add_field_to_hasher(identifier: &Ident) -> Statement { - // `hasher.add({ident})` - let ident = variable_path(path(identifier.clone())); - make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add", // method name - vec![ident], // args - ))) -} - -fn add_cast_to_hasher(identifier: &Ident) -> Statement { - // `hasher.add({ident} as Field)` - // `{ident} as Field` - let cast_operation = cast( - variable_path(path(identifier.clone())), // lhs - UnresolvedTypeData::FieldElement, // rhs - ); - - // `hasher.add({ident} as Field)` - make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add", // method name - vec![cast_operation], // args - ))) -} - -/// Computes the aztec signature for a resolved type. -fn signature_of_type(typ: &Type) -> String { - match typ { - Type::Integer(Signedness::Signed, bit_size) => format!("i{}", bit_size), - Type::Integer(Signedness::Unsigned, bit_size) => format!("u{}", bit_size), - Type::FieldElement => "Field".to_owned(), - Type::Bool => "bool".to_owned(), - Type::Array(len, typ) => { - if let Type::Constant(len) = **len { - format!("[{};{len}]", signature_of_type(typ)) - } else { - unimplemented!("Cannot generate signature for array with length type {:?}", typ) - } - } - Type::Struct(def, args) => { - let fields = def.borrow().get_fields(args); - let fields = vecmap(fields, |(_, typ)| signature_of_type(&typ)); - format!("({})", fields.join(",")) - } - Type::Tuple(types) => { - let fields = vecmap(types, signature_of_type); - format!("({})", fields.join(",")) - } - _ => unimplemented!("Cannot generate signature for type {:?}", typ), - } -} - -/// Computes the signature for a resolved event type. -/// It has the form 'EventName(Field,(Field),[u8;2])' -fn event_signature(event: &StructType) -> String { - let fields = vecmap(event.get_fields(&[]), |(_, typ)| signature_of_type(&typ)); - format!("{}({})", event.name.0.contents, fields.join(",")) -} diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index 5a28d7b779a..57530eb6199 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -4,9 +4,6 @@ pub mod resolution; pub mod scope; pub mod type_check; -#[cfg(feature = "aztec")] -pub(crate) mod aztec_library; - use crate::graph::{CrateGraph, CrateId}; use crate::hir_def::function::FuncMeta; use crate::node_interner::{FuncId, NodeInterner, StructId}; From 927a2a3cf7ebdf5f8350f730a85740b1614eaf86 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:18:38 +0000 Subject: [PATCH 07/38] add aztec feature flag to noirc_driver --- compiler/noirc_driver/Cargo.toml | 5 +++++ compiler/noirc_driver/src/lib.rs | 28 +++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_driver/Cargo.toml b/compiler/noirc_driver/Cargo.toml index 09044b39323..c717efed6f5 100644 --- a/compiler/noirc_driver/Cargo.toml +++ b/compiler/noirc_driver/Cargo.toml @@ -21,3 +21,8 @@ iter-extended.workspace = true fm.workspace = true serde.workspace = true fxhash.workspace = true + +aztec_macros ={path = "../../aztec_macros", optional = true} + +[features] +aztec = ["aztec_macros"] \ No newline at end of file diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 456c2c49609..30187c9fbfd 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -13,6 +13,7 @@ use noirc_evaluator::errors::RuntimeError; use noirc_frontend::graph::{CrateId, CrateName}; use noirc_frontend::hir::def_map::{Contract, CrateDefMap}; use noirc_frontend::hir::Context; +use noirc_frontend::macros_api::MacroProcessor; use noirc_frontend::monomorphization::monomorphize; use noirc_frontend::node_interner::FuncId; use serde::{Deserialize, Serialize}; @@ -121,8 +122,13 @@ pub fn check_crate( crate_id: CrateId, deny_warnings: bool, ) -> CompilationResult<()> { + #[cfg(not(feature = "aztec"))] + let macros: Vec = Vec::new(); + #[cfg(feature = "aztec")] + let macros = vec![aztec_macros::AztecMacro]; + let mut errors = vec![]; - let diagnostics = CrateDefMap::collect_defs(crate_id, context); + let diagnostics = CrateDefMap::collect_defs(crate_id, context, ¯os); errors.extend(diagnostics.into_iter().map(|(error, file_id)| { let diagnostic: CustomDiagnostic = error.into(); diagnostic.in_file(file_id) @@ -357,3 +363,23 @@ pub fn compile_no_check( warnings, }) } + +pub struct DummyMacroProcessor; + +impl MacroProcessor for DummyMacroProcessor { + fn process_untyped_ast( + &self, + _ast: noirc_frontend::parser::SortedModule, + _crate_id: &CrateId, + _context: &Context, + ) -> Result< + noirc_frontend::parser::SortedModule, + (noirc_frontend::macros_api::MacroError, FileId), + > { + unimplemented!("We only use this to satisfy the type checker") + } + + fn process_typed_ast(&self, _crate_id: &CrateId, _context: &mut Context) { + unimplemented!("We only use this to satisfy the type checker") + } +} From b2fb79a11276de632778bfabbad7a7bfbfc6ee20 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:21:37 +0000 Subject: [PATCH 08/38] modify yml feature flags --- .github/workflows/build-aztec-feature-flag.yml | 2 +- .github/workflows/publish-es-packages.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-aztec-feature-flag.yml b/.github/workflows/build-aztec-feature-flag.yml index 888a88a7f88..bacf74ba7b1 100644 --- a/.github/workflows/build-aztec-feature-flag.yml +++ b/.github/workflows/build-aztec-feature-flag.yml @@ -42,4 +42,4 @@ jobs: save-if: ${{ github.event_name != 'merge_group' }} - name: Build with feature flag - run: cargo build --features="noirc_frontend/aztec" + run: cargo build --features="noirc_driver/aztec" diff --git a/.github/workflows/publish-es-packages.yml b/.github/workflows/publish-es-packages.yml index 2e88ee2b77f..f421672c799 100644 --- a/.github/workflows/publish-es-packages.yml +++ b/.github/workflows/publish-es-packages.yml @@ -33,7 +33,7 @@ jobs: - name: Enable aztec features if: ${{ inputs.npm-tag == 'aztec' }} run: | - echo $'\n'"default = [\"aztec\"]"$'\n' >> compiler/noirc_frontend/Cargo.toml + echo $'\n'"default = [\"aztec\"]"$'\n' >> compiler/noirc_driver/Cargo.toml - name: Build wasm package run: | From f3fa65f64f9614f71e64412838f52fedd772a8ba Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:25:55 +0000 Subject: [PATCH 09/38] clippy fix --- aztec_macros/src/lib.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/aztec_macros/src/lib.rs b/aztec_macros/src/lib.rs index c160b241b31..cdb0da454fb 100644 --- a/aztec_macros/src/lib.rs +++ b/aztec_macros/src/lib.rs @@ -265,10 +265,7 @@ fn check_for_compute_note_hash_and_nullifier_definition(module: &SortedModule) - // Array(Option, Box) contains only fields && match &func.def.parameters[3].typ.typ { UnresolvedTypeData::Array(_, inner_type) => { - match inner_type.typ { - UnresolvedTypeData::FieldElement => true, - _ => false, - } + matches!(inner_type.typ, UnresolvedTypeData::FieldElement) }, _ => false, } @@ -278,10 +275,7 @@ fn check_for_compute_note_hash_and_nullifier_definition(module: &SortedModule) - FunctionReturnType::Ty(unresolved_type) => { match &unresolved_type.typ { UnresolvedTypeData::Array(_, inner_type) => { - match inner_type.typ { - UnresolvedTypeData::FieldElement => true, - _ => false, - } + matches!(inner_type.typ, UnresolvedTypeData::FieldElement) }, _ => false, } @@ -310,9 +304,9 @@ fn transform_module( let mut has_transformed_module = false; // Check for a user defined storage struct - let storage_defined = check_for_storage_definition(&module); + let storage_defined = check_for_storage_definition(module); - if storage_defined && !check_for_compute_note_hash_and_nullifier_definition(&module) { + if storage_defined && !check_for_compute_note_hash_and_nullifier_definition(module) { let crate_graph = &context.crate_graph[crate_id]; return Err(( MacroError { @@ -607,7 +601,7 @@ fn create_context(ty: &str, params: &[Param]) -> Vec { // `hasher.add_multiple({ident}.serialize())` UnresolvedTypeData::Named(..) => add_struct_to_hasher(identifier), UnresolvedTypeData::Array(_, arr_type) => { - add_array_to_hasher(identifier, &arr_type) + add_array_to_hasher(identifier, arr_type) } // `hasher.add({ident})` UnresolvedTypeData::FieldElement => add_field_to_hasher(identifier), @@ -908,7 +902,7 @@ fn add_struct_to_hasher(identifier: &Ident) -> Statement { fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { // If this is an array of primitive types (integers / fields) we can add them each to the hasher // casted to a field - let span = var.span.clone(); + let span = var.span; // `array.len()` let end_range_expression = method_call( From 7afdc455f2c624977e2f19052ed589e61c06c9d3 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:35:18 +0000 Subject: [PATCH 10/38] use slice of trait objects when there are no macro processors --- compiler/noirc_driver/src/lib.rs | 25 ++----------------------- compiler/noirc_frontend/src/tests.rs | 23 ++++------------------- 2 files changed, 6 insertions(+), 42 deletions(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 30187c9fbfd..2e55d583b5f 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -13,7 +13,6 @@ use noirc_evaluator::errors::RuntimeError; use noirc_frontend::graph::{CrateId, CrateName}; use noirc_frontend::hir::def_map::{Contract, CrateDefMap}; use noirc_frontend::hir::Context; -use noirc_frontend::macros_api::MacroProcessor; use noirc_frontend::monomorphization::monomorphize; use noirc_frontend::node_interner::FuncId; use serde::{Deserialize, Serialize}; @@ -123,7 +122,7 @@ pub fn check_crate( deny_warnings: bool, ) -> CompilationResult<()> { #[cfg(not(feature = "aztec"))] - let macros: Vec = Vec::new(); + let macros: Vec<&dyn MacroProcessor> = Vec::new(); #[cfg(feature = "aztec")] let macros = vec![aztec_macros::AztecMacro]; @@ -362,24 +361,4 @@ pub fn compile_no_check( noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), warnings, }) -} - -pub struct DummyMacroProcessor; - -impl MacroProcessor for DummyMacroProcessor { - fn process_untyped_ast( - &self, - _ast: noirc_frontend::parser::SortedModule, - _crate_id: &CrateId, - _context: &Context, - ) -> Result< - noirc_frontend::parser::SortedModule, - (noirc_frontend::macros_api::MacroError, FileId), - > { - unimplemented!("We only use this to satisfy the type checker") - } - - fn process_typed_ast(&self, _crate_id: &CrateId, _context: &mut Context) { - unimplemented!("We only use this to satisfy the type checker") - } -} +} \ No newline at end of file diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 7223718a79d..55044ac8df8 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -55,24 +55,6 @@ mod test { .collect() } - struct DummyMacroProcessor; - - impl MacroProcessor for DummyMacroProcessor { - fn process_untyped_ast( - &self, - ast: crate::macros_api::SortedModule, - crate_id: &crate::graph::CrateId, - context: &Context, - ) -> Result - { - unimplemented!() - } - - fn process_typed_ast(&self, crate_id: &crate::graph::CrateId, context: &mut Context) { - unimplemented!() - } - } - pub(crate) fn get_program( src: &str, ) -> (ParsedModule, Context, Vec<(CompilationError, FileId)>) { @@ -98,13 +80,16 @@ mod test { krate: root_crate_id, extern_prelude: BTreeMap::new(), }; + + let empty_macro_processors: Vec<&dyn MacroProcessor> = Vec::new(); + // Now we want to populate the CrateDefMap using the DefCollector errors.extend(DefCollector::collect( def_map, &mut context, program.clone().into_sorted(), root_file_id, - &Vec::::new(), + &empty_macro_processors, )); } (program, context, errors) From 7df00c77faa6a397c09ed1f1c8a354131bb3f623 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:42:59 +0000 Subject: [PATCH 11/38] replace opaque type with trait object in function signature --- compiler/noirc_driver/src/lib.rs | 7 ++++--- compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs | 2 +- compiler/noirc_frontend/src/hir/def_map/mod.rs | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 2e55d583b5f..ac138b8c265 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -13,6 +13,7 @@ use noirc_evaluator::errors::RuntimeError; use noirc_frontend::graph::{CrateId, CrateName}; use noirc_frontend::hir::def_map::{Contract, CrateDefMap}; use noirc_frontend::hir::Context; +use noirc_frontend::macros_api::MacroProcessor; use noirc_frontend::monomorphization::monomorphize; use noirc_frontend::node_interner::FuncId; use serde::{Deserialize, Serialize}; @@ -122,12 +123,12 @@ pub fn check_crate( deny_warnings: bool, ) -> CompilationResult<()> { #[cfg(not(feature = "aztec"))] - let macros: Vec<&dyn MacroProcessor> = Vec::new(); + let macros: &[&dyn MacroProcessor] = &[]; #[cfg(feature = "aztec")] - let macros = vec![aztec_macros::AztecMacro]; + let macros = &[aztec_macros::AztecMacro]; let mut errors = vec![]; - let diagnostics = CrateDefMap::collect_defs(crate_id, context, ¯os); + let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); errors.extend(diagnostics.into_iter().map(|(error, file_id)| { let diagnostic: CustomDiagnostic = error.into(); diagnostic.in_file(file_id) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index e3105342db2..48fc7f43728 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -200,7 +200,7 @@ impl DefCollector { context: &mut Context, ast: SortedModule, root_file_id: FileId, - macro_processors: &[impl MacroProcessor], + macro_processors: &[&dyn MacroProcessor], ) -> Vec<(CompilationError, FileId)> { let mut errors: Vec<(CompilationError, FileId)> = vec![]; let crate_id = def_map.krate; diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 5f6f3f3cf2a..8945bf48098 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -72,7 +72,7 @@ impl CrateDefMap { pub fn collect_defs( crate_id: CrateId, context: &mut Context, - macro_processors: &[impl MacroProcessor], + macro_processors: &[&dyn MacroProcessor], ) -> Vec<(CompilationError, FileId)> { // Check if this Crate has already been compiled // XXX: There is probably a better alternative for this. From 7c9198fd487f72925d993ab5c8a9b61e407974d2 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:43:25 +0000 Subject: [PATCH 12/38] fmt --- compiler/noirc_driver/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index ac138b8c265..85914213481 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -362,4 +362,4 @@ pub fn compile_no_check( noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), warnings, }) -} \ No newline at end of file +} From e6b4b89436e94b2e7139b735eee3d0bc6f23d8ee Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:53:49 +0000 Subject: [PATCH 13/38] temporarily coerce the type system -- a clone here would likely not be that bad, since each Macro processor is a pointer to a vtable --- compiler/noirc_driver/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 85914213481..d7481eca6de 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -123,12 +123,14 @@ pub fn check_crate( deny_warnings: bool, ) -> CompilationResult<()> { #[cfg(not(feature = "aztec"))] - let macros: &[&dyn MacroProcessor] = &[]; + let macros: Vec<&dyn MacroProcessor> = Vec::new(); #[cfg(feature = "aztec")] - let macros = &[aztec_macros::AztecMacro]; + let macros = vec![aztec_macros::AztecMacro]; + #[cfg(feature = "aztec")] + let macros : Vec<&dyn MacroProcessor> = macros.iter().map(|m| m as &dyn MacroProcessor).collect(); let mut errors = vec![]; - let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); + let diagnostics = CrateDefMap::collect_defs(crate_id, context, ¯os); errors.extend(diagnostics.into_iter().map(|(error, file_id)| { let diagnostic: CustomDiagnostic = error.into(); diagnostic.in_file(file_id) From 89b467832ded2ac0fecac6ba0e57ddd2c5981cdc Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 18:54:13 +0000 Subject: [PATCH 14/38] fmt --- compiler/noirc_driver/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index d7481eca6de..146d5620b15 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -127,7 +127,8 @@ pub fn check_crate( #[cfg(feature = "aztec")] let macros = vec![aztec_macros::AztecMacro]; #[cfg(feature = "aztec")] - let macros : Vec<&dyn MacroProcessor> = macros.iter().map(|m| m as &dyn MacroProcessor).collect(); + let macros: Vec<&dyn MacroProcessor> = + macros.iter().map(|m| m as &dyn MacroProcessor).collect(); let mut errors = vec![]; let diagnostics = CrateDefMap::collect_defs(crate_id, context, ¯os); From 00136a12032335e06b8de58ea732f06ce68ca982 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 19:01:20 +0000 Subject: [PATCH 15/38] use vec instead of slice and clone the pointers to vtable (references) -- this should be fairly cheap --- compiler/noirc_driver/src/lib.rs | 7 ++----- compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs | 4 ++-- compiler/noirc_frontend/src/hir/def_map/mod.rs | 6 +++--- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 146d5620b15..93ed26fb91a 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -125,13 +125,10 @@ pub fn check_crate( #[cfg(not(feature = "aztec"))] let macros: Vec<&dyn MacroProcessor> = Vec::new(); #[cfg(feature = "aztec")] - let macros = vec![aztec_macros::AztecMacro]; - #[cfg(feature = "aztec")] - let macros: Vec<&dyn MacroProcessor> = - macros.iter().map(|m| m as &dyn MacroProcessor).collect(); + let macros = vec![&aztec_macros::AztecMacro as &dyn MacroProcessor]; let mut errors = vec![]; - let diagnostics = CrateDefMap::collect_defs(crate_id, context, ¯os); + let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); errors.extend(diagnostics.into_iter().map(|(error, file_id)| { let diagnostic: CustomDiagnostic = error.into(); diagnostic.in_file(file_id) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 48fc7f43728..1ffd8aad28d 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -200,7 +200,7 @@ impl DefCollector { context: &mut Context, ast: SortedModule, root_file_id: FileId, - macro_processors: &[&dyn MacroProcessor], + macro_processors: Vec<&dyn MacroProcessor>, ) -> Vec<(CompilationError, FileId)> { let mut errors: Vec<(CompilationError, FileId)> = vec![]; let crate_id = def_map.krate; @@ -213,7 +213,7 @@ impl DefCollector { let crate_graph = &context.crate_graph[crate_id]; for dep in crate_graph.dependencies.clone() { - errors.extend(CrateDefMap::collect_defs(dep.crate_id, context, macro_processors)); + errors.extend(CrateDefMap::collect_defs(dep.crate_id, context, macro_processors.clone())); let dep_def_root = context.def_map(&dep.crate_id).expect("ice: def map was just created").root; diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 8945bf48098..de1cac0393f 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -72,7 +72,7 @@ impl CrateDefMap { pub fn collect_defs( crate_id: CrateId, context: &mut Context, - macro_processors: &[&dyn MacroProcessor], + macro_processors: Vec<&dyn MacroProcessor>, ) -> Vec<(CompilationError, FileId)> { // Check if this Crate has already been compiled // XXX: There is probably a better alternative for this. @@ -89,7 +89,7 @@ impl CrateDefMap { let (ast, parsing_errors) = parse_file(&context.file_manager, root_file_id); let mut ast = ast.into_sorted(); - for macro_processor in macro_processors { + for macro_processor in ¯o_processors { ast = match macro_processor.process_untyped_ast(ast, &crate_id, context) { Ok(ast) => ast, Err((error, file_id)) => { @@ -113,7 +113,7 @@ impl CrateDefMap { }; // Now we want to populate the CrateDefMap using the DefCollector - errors.extend(DefCollector::collect(def_map, context, ast, root_file_id, macro_processors)); + errors.extend(DefCollector::collect(def_map, context, ast, root_file_id, macro_processors.clone())); errors.extend( parsing_errors.iter().map(|e| (e.clone().into(), root_file_id)).collect::>(), From cf11ad9a41a450ad6833e430aca4b686b536dd44 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 19:02:00 +0000 Subject: [PATCH 16/38] fmt --- compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs | 6 +++++- compiler/noirc_frontend/src/hir/def_map/mod.rs | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 1ffd8aad28d..5e417299bd9 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -213,7 +213,11 @@ impl DefCollector { let crate_graph = &context.crate_graph[crate_id]; for dep in crate_graph.dependencies.clone() { - errors.extend(CrateDefMap::collect_defs(dep.crate_id, context, macro_processors.clone())); + errors.extend(CrateDefMap::collect_defs( + dep.crate_id, + context, + macro_processors.clone(), + )); let dep_def_root = context.def_map(&dep.crate_id).expect("ice: def map was just created").root; diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index de1cac0393f..5f38c80a5fe 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -113,7 +113,13 @@ impl CrateDefMap { }; // Now we want to populate the CrateDefMap using the DefCollector - errors.extend(DefCollector::collect(def_map, context, ast, root_file_id, macro_processors.clone())); + errors.extend(DefCollector::collect( + def_map, + context, + ast, + root_file_id, + macro_processors.clone(), + )); errors.extend( parsing_errors.iter().map(|e| (e.clone().into(), root_file_id)).collect::>(), From a925d8d6819ca6a05b60a731929134579634c1d3 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sun, 26 Nov 2023 19:07:50 +0000 Subject: [PATCH 17/38] remove extraneous & in test --- compiler/noirc_frontend/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 55044ac8df8..13ce71c4616 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -89,7 +89,7 @@ mod test { &mut context, program.clone().into_sorted(), root_file_id, - &empty_macro_processors, + empty_macro_processors, )); } (program, context, errors) From 546020d1666ac0718097aff6d1777882cb0125da Mon Sep 17 00:00:00 2001 From: kevaundray Date: Mon, 27 Nov 2023 23:09:28 +0000 Subject: [PATCH 18/38] remove aztec feature flag --- compiler/noirc_driver/Cargo.toml | 5 +---- compiler/noirc_driver/src/lib.rs | 18 ++++++++++++------ tooling/lsp/src/lib.rs | 2 ++ tooling/lsp/src/notifications/mod.rs | 9 +++++---- tooling/lsp/src/requests/code_lens_request.rs | 2 +- tooling/lsp/src/requests/profile_run.rs | 4 +++- tooling/lsp/src/requests/test_run.rs | 2 +- tooling/lsp/src/requests/tests.rs | 2 +- tooling/nargo_cli/src/cli/check_cmd.rs | 4 +++- tooling/nargo_cli/src/cli/test_cmd.rs | 1 + 10 files changed, 30 insertions(+), 19 deletions(-) diff --git a/compiler/noirc_driver/Cargo.toml b/compiler/noirc_driver/Cargo.toml index c717efed6f5..63d503fc7d9 100644 --- a/compiler/noirc_driver/Cargo.toml +++ b/compiler/noirc_driver/Cargo.toml @@ -22,7 +22,4 @@ fm.workspace = true serde.workspace = true fxhash.workspace = true -aztec_macros ={path = "../../aztec_macros", optional = true} - -[features] -aztec = ["aztec_macros"] \ No newline at end of file +aztec_macros ={path = "../../aztec_macros"} \ No newline at end of file diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 93ed26fb91a..427806212cf 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -61,6 +61,10 @@ pub struct CompileOptions { /// Suppress warnings #[arg(long, conflicts_with = "deny_warnings")] pub silence_warnings: bool, + + /// Enables the aztec macro preprocessor + #[arg(long, hide = true)] + pub aztec_macro: bool, } /// Helper type used to signify where only warnings are expected in file diagnostics @@ -121,11 +125,12 @@ pub fn check_crate( context: &mut Context, crate_id: CrateId, deny_warnings: bool, + enable_aztec_macro: bool, ) -> CompilationResult<()> { - #[cfg(not(feature = "aztec"))] - let macros: Vec<&dyn MacroProcessor> = Vec::new(); - #[cfg(feature = "aztec")] - let macros = vec![&aztec_macros::AztecMacro as &dyn MacroProcessor]; + let mut macros: Vec<&dyn MacroProcessor> = Vec::new(); + if enable_aztec_macro { + macros.push(&aztec_macros::AztecMacro as &dyn MacroProcessor); + } let mut errors = vec![]; let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); @@ -161,7 +166,8 @@ pub fn compile_main( cached_program: Option, force_compile: bool, ) -> CompilationResult { - let (_, mut warnings) = check_crate(context, crate_id, options.deny_warnings)?; + let (_, mut warnings) = + check_crate(context, crate_id, options.deny_warnings, options.aztec_macro)?; let main = context.get_main_function(&crate_id).ok_or_else(|| { // TODO(#2155): This error might be a better to exist in Nargo @@ -194,7 +200,7 @@ pub fn compile_contract( crate_id: CrateId, options: &CompileOptions, ) -> CompilationResult { - let (_, warnings) = check_crate(context, crate_id, options.deny_warnings)?; + let (_, warnings) = check_crate(context, crate_id, options.deny_warnings, options.aztec_macro)?; // TODO: We probably want to error if contracts is empty let contracts = context.get_all_contracts(&crate_id); diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index d8a992155dd..791fa41c1a5 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -46,6 +46,7 @@ pub struct LspState { root_path: Option, client: ClientSocket, solver: WrapperSolver, + enable_aztec_macro: bool, input_files: HashMap, } @@ -55,6 +56,7 @@ impl LspState { client: client.clone(), root_path: None, solver: WrapperSolver(Box::new(solver)), + enable_aztec_macro: false, input_files: HashMap::new(), } } diff --git a/tooling/lsp/src/notifications/mod.rs b/tooling/lsp/src/notifications/mod.rs index f6484f49d48..b1c70b7e175 100644 --- a/tooling/lsp/src/notifications/mod.rs +++ b/tooling/lsp/src/notifications/mod.rs @@ -113,10 +113,11 @@ pub(super) fn on_did_save_text_document( .flat_map(|package| -> Vec { let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); - let file_diagnostics = match check_crate(&mut context, crate_id, false) { - Ok(((), warnings)) => warnings, - Err(errors_and_warnings) => errors_and_warnings, - }; + let file_diagnostics = + match check_crate(&mut context, crate_id, false, state.enable_aztec_macro) { + Ok(((), warnings)) => warnings, + Err(errors_and_warnings) => errors_and_warnings, + }; // We don't add test headings for a package if it contains no `#[test]` functions if let Some(tests) = get_package_tests_in_crate(&context, &crate_id, &package.name) { diff --git a/tooling/lsp/src/requests/code_lens_request.rs b/tooling/lsp/src/requests/code_lens_request.rs index 602ed268981..43577cb1126 100644 --- a/tooling/lsp/src/requests/code_lens_request.rs +++ b/tooling/lsp/src/requests/code_lens_request.rs @@ -86,7 +86,7 @@ fn on_code_lens_request_inner( let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation for producing code lenses // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, false); + let _ = check_crate(&mut context, crate_id, false, state.enable_aztec_macro); let fm = &context.file_manager; let files = fm.as_file_map(); diff --git a/tooling/lsp/src/requests/profile_run.rs b/tooling/lsp/src/requests/profile_run.rs index 84888d30ba5..a648df8b65f 100644 --- a/tooling/lsp/src/requests/profile_run.rs +++ b/tooling/lsp/src/requests/profile_run.rs @@ -61,13 +61,15 @@ fn on_profile_run_request_inner( let is_opcode_supported = |_opcode: &Opcode| true; let np_language = Language::PLONKCSat { width: 3 }; + let compile_options = + CompileOptions { aztec_macro: state.enable_aztec_macro, ..Default::default() }; let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace( &workspace, &binary_packages, &contract_packages, np_language, is_opcode_supported, - &CompileOptions::default(), + &compile_options, ) .map_err(|err| ResponseError::new(ErrorCode::REQUEST_FAILED, err))?; diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index 962fe99a49b..d7a61d315a8 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -52,7 +52,7 @@ fn on_test_run_request_inner( match workspace.into_iter().next() { Some(package) => { let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); - if check_crate(&mut context, crate_id, false).is_err() { + if check_crate(&mut context, crate_id, false, state.enable_aztec_macro).is_err() { let result = NargoTestRunResult { id: params.id.clone(), result: "error".to_string(), diff --git a/tooling/lsp/src/requests/tests.rs b/tooling/lsp/src/requests/tests.rs index 6b94b921a06..f290e6ebb6e 100644 --- a/tooling/lsp/src/requests/tests.rs +++ b/tooling/lsp/src/requests/tests.rs @@ -56,7 +56,7 @@ fn on_tests_request_inner( let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation for producing tests // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, false); + let _ = check_crate(&mut context, crate_id, false, state.enable_aztec_macro); // We don't add test headings for a package if it contains no `#[test]` functions get_package_tests_in_crate(&context, &crate_id, &package.name) diff --git a/tooling/nargo_cli/src/cli/check_cmd.rs b/tooling/nargo_cli/src/cli/check_cmd.rs index 57b36b8932b..451cdc1c2cc 100644 --- a/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/tooling/nargo_cli/src/cli/check_cmd.rs @@ -62,6 +62,7 @@ fn check_package(package: &Package, compile_options: &CompileOptions) -> Result< crate_id, compile_options.deny_warnings, compile_options.silence_warnings, + compile_options.aztec_macro, )?; if package.is_library() || package.is_contract() { @@ -183,8 +184,9 @@ pub(crate) fn check_crate_and_report_errors( crate_id: CrateId, deny_warnings: bool, silence_warnings: bool, + enable_aztec_macro: bool, ) -> Result<(), CompileError> { - let result = check_crate(context, crate_id, deny_warnings); + let result = check_crate(context, crate_id, deny_warnings, enable_aztec_macro); super::compile_cmd::report_errors( result, &context.file_manager, diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index e117d8555a5..db3e20d1d77 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -93,6 +93,7 @@ fn run_tests( crate_id, compile_options.deny_warnings, compile_options.silence_warnings, + compile_options.aztec_macro, )?; let test_functions = context.get_all_test_functions_in_crate_matching(&crate_id, test_name); From 958e11fac32313bdcbab7f3b04f9b66b31956b8f Mon Sep 17 00:00:00 2001 From: kevaundray Date: Mon, 27 Nov 2023 23:09:41 +0000 Subject: [PATCH 19/38] remove aztec builds from CI workflow --- .../workflows/build-aztec-feature-flag.yml | 45 ------------------- .github/workflows/publish-es-packages.yml | 5 --- 2 files changed, 50 deletions(-) delete mode 100644 .github/workflows/build-aztec-feature-flag.yml diff --git a/.github/workflows/build-aztec-feature-flag.yml b/.github/workflows/build-aztec-feature-flag.yml deleted file mode 100644 index bacf74ba7b1..00000000000 --- a/.github/workflows/build-aztec-feature-flag.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Build with aztec feature flag - -on: - pull_request: - merge_group: - push: - branches: - - master - -# This will cancel previous runs when a branch or PR is updated -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - build-aztec-feature-flag: - name: Test on ${{ matrix.os }} - runs-on: ${{ matrix.runner }} - timeout-minutes: 30 - - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu - runner: ubuntu-latest - target: x86_64-unknown-linux-gnu - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup toolchain - uses: dtolnay/rust-toolchain@1.71.1 - with: - targets: ${{ matrix.target }} - - - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }} - cache-on-failure: true - save-if: ${{ github.event_name != 'merge_group' }} - - - name: Build with feature flag - run: cargo build --features="noirc_driver/aztec" diff --git a/.github/workflows/publish-es-packages.yml b/.github/workflows/publish-es-packages.yml index f421672c799..e360654b46a 100644 --- a/.github/workflows/publish-es-packages.yml +++ b/.github/workflows/publish-es-packages.yml @@ -30,11 +30,6 @@ jobs: nix-cache-name: "noir" cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} - - name: Enable aztec features - if: ${{ inputs.npm-tag == 'aztec' }} - run: | - echo $'\n'"default = [\"aztec\"]"$'\n' >> compiler/noirc_driver/Cargo.toml - - name: Build wasm package run: | nix build -L .#noir_wasm From 0684bf4e67ebea728b5554b3664409777daae203 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Mon, 27 Nov 2023 23:50:37 +0000 Subject: [PATCH 20/38] Update compiler/noirc_driver/Cargo.toml --- compiler/noirc_driver/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_driver/Cargo.toml b/compiler/noirc_driver/Cargo.toml index 63d503fc7d9..314418554ba 100644 --- a/compiler/noirc_driver/Cargo.toml +++ b/compiler/noirc_driver/Cargo.toml @@ -22,4 +22,4 @@ fm.workspace = true serde.workspace = true fxhash.workspace = true -aztec_macros ={path = "../../aztec_macros"} \ No newline at end of file +aztec_macros = { path = "../../aztec_macros" } \ No newline at end of file From 26559c35d189da2bfe7ca503b6262848f0466016 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 28 Nov 2023 00:10:00 +0000 Subject: [PATCH 21/38] remove duplicated code --- aztec_macros/src/lib.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/aztec_macros/src/lib.rs b/aztec_macros/src/lib.rs index cdb0da454fb..f55feb9801e 100644 --- a/aztec_macros/src/lib.rs +++ b/aztec_macros/src/lib.rs @@ -244,7 +244,7 @@ fn check_for_aztec_dependency( if has_aztec_dependency { Ok(()) } else { - Err((MacroError { primary_message: "Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml".to_owned(), secondary_message: None, span: None }, crate_graph.root_file_id)) + Err((AztecMacroError::AztecNotFound.into(), crate_graph.root_file_id)) } } @@ -309,11 +309,8 @@ fn transform_module( if storage_defined && !check_for_compute_note_hash_and_nullifier_definition(module) { let crate_graph = &context.crate_graph[crate_id]; return Err(( - MacroError { - span: Some(Span::default()), // Add a default span so we know which contract file the error originates from - primary_message: "compute_note_hash_and_nullifier function not found. Define it in your contract.".to_owned(), - secondary_message: None, - }, + AztecMacroError::AztecComputeNoteHashAndNullifierNotFound { span: Span::default() } + .into(), crate_graph.root_file_id, )); } From d6ebf4ffa722f306993d98fe6ca70913924dbd7b Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 28 Nov 2023 23:04:49 +0000 Subject: [PATCH 22/38] add aztec macros flag for compiling in typescript --- compiler/wasm/src/compile.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index e7fd3dd5212..46d3da2780c 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -136,6 +136,7 @@ pub fn compile( entry_point: String, contracts: Option, dependency_graph: Option, + enable_aztec_macro : bool, ) -> Result { console_error_panic_hook::set_once(); @@ -156,7 +157,7 @@ pub fn compile( process_dependency_graph(&mut context, dependency_graph); - let compile_options = CompileOptions::default(); + let compile_options = CompileOptions { aztec_macro: enable_aztec_macro, ..Default::default() }; // For now we default to plonk width = 3, though we can add it as a parameter let np_language = acvm::Language::PLONKCSat { width: 3 }; From 8c7a7c4e63ce7b299050f0827406cd33b52e4235 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Wed, 29 Nov 2023 15:27:22 +0000 Subject: [PATCH 23/38] cargo fmt --all --- compiler/wasm/src/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index 46d3da2780c..52184a7f8e7 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -136,7 +136,7 @@ pub fn compile( entry_point: String, contracts: Option, dependency_graph: Option, - enable_aztec_macro : bool, + enable_aztec_macro: bool, ) -> Result { console_error_panic_hook::set_once(); From 8beb2769ca830314477a39a913773e5eccc931b4 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Wed, 29 Nov 2023 15:32:11 +0000 Subject: [PATCH 24/38] default to enabling the macro on lsp run --- tooling/lsp/src/lib.rs | 8 ++++---- tooling/nargo_cli/src/cli/lsp_cmd.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index 791fa41c1a5..830b3c2865b 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -51,12 +51,12 @@ pub struct LspState { } impl LspState { - fn new(client: &ClientSocket, solver: impl BlackBoxFunctionSolver + 'static) -> Self { + fn new(client: &ClientSocket, solver: impl BlackBoxFunctionSolver + 'static, enable_aztec_macro : bool) -> Self { Self { client: client.clone(), root_path: None, solver: WrapperSolver(Box::new(solver)), - enable_aztec_macro: false, + enable_aztec_macro, input_files: HashMap::new(), } } @@ -67,8 +67,8 @@ pub struct NargoLspService { } impl NargoLspService { - pub fn new(client: &ClientSocket, solver: impl BlackBoxFunctionSolver + 'static) -> Self { - let state = LspState::new(client, solver); + pub fn new(client: &ClientSocket, solver: impl BlackBoxFunctionSolver + 'static,enable_aztec_macro : bool) -> Self { + let state = LspState::new(client, solver, enable_aztec_macro); let mut router = Router::new(state); router .request::(on_initialize) diff --git a/tooling/nargo_cli/src/cli/lsp_cmd.rs b/tooling/nargo_cli/src/cli/lsp_cmd.rs index a41bb877991..442eae1e508 100644 --- a/tooling/nargo_cli/src/cli/lsp_cmd.rs +++ b/tooling/nargo_cli/src/cli/lsp_cmd.rs @@ -32,7 +32,7 @@ pub(crate) fn run( let (server, _) = async_lsp::MainLoop::new_server(|client| { #[allow(deprecated)] let blackbox_solver = barretenberg_blackbox_solver::BarretenbergSolver::new(); - let router = NargoLspService::new(&client, blackbox_solver); + let router = NargoLspService::new(&client, blackbox_solver, true); ServiceBuilder::new() .layer(TracingLayer::default()) From 2c4e84b3fcf71a9b2703649820e2698947453c06 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Thu, 30 Nov 2023 17:44:31 +0000 Subject: [PATCH 25/38] fix test --- tooling/lsp/src/requests/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index a319f2593a4..522563de9d0 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -120,7 +120,7 @@ mod initialization { async fn test_on_initialize() { let client = ClientSocket::new_closed(); let solver = MockBackend; - let mut state = LspState::new(&client, solver); + let mut state = LspState::new(&client, solver, false); let params = InitializeParams::default(); let response = on_initialize(&mut state, params).await.unwrap(); assert!(matches!( From f5060a22b2ba113949c088a1de2b544499efccf3 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Thu, 30 Nov 2023 17:45:25 +0000 Subject: [PATCH 26/38] fmt --- tooling/lsp/src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index 830b3c2865b..5ca938c8100 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -51,7 +51,11 @@ pub struct LspState { } impl LspState { - fn new(client: &ClientSocket, solver: impl BlackBoxFunctionSolver + 'static, enable_aztec_macro : bool) -> Self { + fn new( + client: &ClientSocket, + solver: impl BlackBoxFunctionSolver + 'static, + enable_aztec_macro: bool, + ) -> Self { Self { client: client.clone(), root_path: None, @@ -67,7 +71,11 @@ pub struct NargoLspService { } impl NargoLspService { - pub fn new(client: &ClientSocket, solver: impl BlackBoxFunctionSolver + 'static,enable_aztec_macro : bool) -> Self { + pub fn new( + client: &ClientSocket, + solver: impl BlackBoxFunctionSolver + 'static, + enable_aztec_macro: bool, + ) -> Self { let state = LspState::new(client, solver, enable_aztec_macro); let mut router = Router::new(state); router From 5746d405e5ae1c224c29059b12e1008b4977816d Mon Sep 17 00:00:00 2001 From: kevaundray Date: Thu, 30 Nov 2023 19:43:23 +0000 Subject: [PATCH 27/38] enable aztec macro via an environment variable --- Cargo.toml | 2 +- compiler/noirc_driver/src/lib.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5738fe94984..a9bf4b8041a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,7 +96,7 @@ getrandom = "0.2" cfg-if = "1.0.0" -clap = { version = "4.3.19", features = ["derive"] } +clap = { version = "4.3.19", features = ["derive", "env"] } codespan = { version = "0.11.1", features = ["serialization"] } codespan-lsp = "0.11.1" codespan-reporting = "0.11.1" diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 427806212cf..8a5d1b9ebef 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -63,10 +63,17 @@ pub struct CompileOptions { pub silence_warnings: bool, /// Enables the aztec macro preprocessor - #[arg(long, hide = true)] + #[arg(long, env = AZTEC_MACRO_ENV_VAR, hide = true)] pub aztec_macro: bool, } +pub(crate) const AZTEC_MACRO_ENV_VAR: &str = "AZTEC_MACROS"; + +/// Returns true if the `AZTEC_MACROS` environment variable is set. +pub fn is_aztec_environment_variable_set() -> bool { + std::env::var(AZTEC_MACRO_ENV_VAR).is_ok() +} + /// Helper type used to signify where only warnings are expected in file diagnostics pub type Warnings = Vec; From 1aa22065eff965b3ecab40e644705a2a9647c519 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Thu, 30 Nov 2023 19:47:32 +0000 Subject: [PATCH 28/38] set the aztec macro based on environment variable for lsp --- tooling/nargo_cli/src/cli/lsp_cmd.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tooling/nargo_cli/src/cli/lsp_cmd.rs b/tooling/nargo_cli/src/cli/lsp_cmd.rs index 442eae1e508..c274c5e941c 100644 --- a/tooling/nargo_cli/src/cli/lsp_cmd.rs +++ b/tooling/nargo_cli/src/cli/lsp_cmd.rs @@ -4,6 +4,7 @@ use async_lsp::{ }; use clap::Args; use noir_lsp::NargoLspService; +use noirc_driver::is_aztec_environment_variable_set; use tower::ServiceBuilder; use super::NargoConfig; @@ -32,7 +33,8 @@ pub(crate) fn run( let (server, _) = async_lsp::MainLoop::new_server(|client| { #[allow(deprecated)] let blackbox_solver = barretenberg_blackbox_solver::BarretenbergSolver::new(); - let router = NargoLspService::new(&client, blackbox_solver, true); + let router = + NargoLspService::new(&client, blackbox_solver, is_aztec_environment_variable_set()); ServiceBuilder::new() .layer(TracingLayer::default()) From 58fe17bb1cbf9a911cb4724968f3fb0fd91e2294 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Fri, 1 Dec 2023 12:53:43 +0000 Subject: [PATCH 29/38] add missing args --- compiler/wasm/test/node/index.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/wasm/test/node/index.test.ts b/compiler/wasm/test/node/index.test.ts index c0d5f88e407..e8442780b9b 100644 --- a/compiler/wasm/test/node/index.test.ts +++ b/compiler/wasm/test/node/index.test.ts @@ -21,7 +21,7 @@ async function getPrecompiledSource(path: string): Promise { describe('noir wasm compilation', () => { describe('can compile simple scripts', () => { it('matching nargos compilation', async () => { - const wasmCircuit = await compile(join(__dirname, simpleScriptSourcePath)); + const wasmCircuit = await compile(join(__dirname, simpleScriptSourcePath), undefined, undefined, false); const cliCircuit = await getPrecompiledSource(simpleScriptExpectedArtifact); if (!('program' in wasmCircuit)) { @@ -61,7 +61,7 @@ describe('noir wasm compilation', () => { library_dependencies: { lib_a: ['lib_b'], }, - }); + },false); const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); From 14d846b39ab951eb46851042bc22ecda00bc7526 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Fri, 1 Dec 2023 12:56:52 +0000 Subject: [PATCH 30/38] lint fix --- compiler/wasm/test/node/index.test.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/wasm/test/node/index.test.ts b/compiler/wasm/test/node/index.test.ts index e8442780b9b..4c9ce418cb8 100644 --- a/compiler/wasm/test/node/index.test.ts +++ b/compiler/wasm/test/node/index.test.ts @@ -56,12 +56,17 @@ describe('noir wasm compilation', () => { }); it('matching nargos compilation', async () => { - const wasmCircuit = await compile('/script/main.nr', false, { - root_dependencies: ['lib_a'], - library_dependencies: { - lib_a: ['lib_b'], + const wasmCircuit = await compile( + '/script/main.nr', + false, + { + root_dependencies: ['lib_a'], + library_dependencies: { + lib_a: ['lib_b'], + }, }, - },false); + false, + ); const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); From f7a8f9f6cffbf3d676343ff276030d336154855b Mon Sep 17 00:00:00 2001 From: Tom French Date: Tue, 12 Dec 2023 12:56:34 +0000 Subject: [PATCH 31/38] chore: fix missing arg --- tooling/lsp/src/requests/goto_definition.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index 4e615cd4fe5..8f4b6131c2f 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -56,7 +56,7 @@ fn on_goto_definition_inner( nargo::prepare_package(package, Box::new(crate::get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false); + let _ = noirc_driver::check_crate(&mut context, crate_id, false, state.enable_aztec_macro); let files = context.file_manager.as_file_map(); let file_id = context.file_manager.name_to_id(file_path.clone()); From 8f99af1c49f22853fcf48dd870ba6e495ec1886d Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Dec 2023 17:41:52 +0000 Subject: [PATCH 32/38] Empty commit to signal me making changes From 7f4a1f99716435bdde7f21f821801f252d84c11d Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Dec 2023 17:43:38 +0000 Subject: [PATCH 33/38] remove threading of aztec macros flag --- compiler/noirc_driver/src/lib.rs | 21 +++---------------- compiler/wasm/src/compile.rs | 2 +- tooling/lsp/src/lib.rs | 16 +++----------- tooling/lsp/src/notifications/mod.rs | 9 ++++---- tooling/lsp/src/requests/code_lens_request.rs | 2 +- tooling/lsp/src/requests/goto_definition.rs | 2 +- tooling/lsp/src/requests/mod.rs | 2 +- tooling/lsp/src/requests/profile_run.rs | 3 +-- tooling/lsp/src/requests/test_run.rs | 2 +- tooling/lsp/src/requests/tests.rs | 2 +- tooling/nargo_cli/src/cli/check_cmd.rs | 4 +--- tooling/nargo_cli/src/cli/lsp_cmd.rs | 4 +--- tooling/nargo_cli/src/cli/test_cmd.rs | 1 - 13 files changed, 19 insertions(+), 51 deletions(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index f1b6951a4c7..bf1bafb834b 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -61,17 +61,6 @@ pub struct CompileOptions { /// Suppress warnings #[arg(long, conflicts_with = "deny_warnings")] pub silence_warnings: bool, - - /// Enables the aztec macro preprocessor - #[arg(long, env = AZTEC_MACRO_ENV_VAR, hide = true)] - pub aztec_macro: bool, -} - -pub(crate) const AZTEC_MACRO_ENV_VAR: &str = "AZTEC_MACROS"; - -/// Returns true if the `AZTEC_MACROS` environment variable is set. -pub fn is_aztec_environment_variable_set() -> bool { - std::env::var(AZTEC_MACRO_ENV_VAR).is_ok() } /// Helper type used to signify where only warnings are expected in file diagnostics @@ -132,12 +121,9 @@ pub fn check_crate( context: &mut Context, crate_id: CrateId, deny_warnings: bool, - enable_aztec_macro: bool, ) -> CompilationResult<()> { let mut macros: Vec<&dyn MacroProcessor> = Vec::new(); - if enable_aztec_macro { - macros.push(&aztec_macros::AztecMacro as &dyn MacroProcessor); - } + macros.push(&aztec_macros::AztecMacro as &dyn MacroProcessor); let mut errors = vec![]; let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); @@ -173,8 +159,7 @@ pub fn compile_main( cached_program: Option, force_compile: bool, ) -> CompilationResult { - let (_, mut warnings) = - check_crate(context, crate_id, options.deny_warnings, options.aztec_macro)?; + let (_, mut warnings) = check_crate(context, crate_id, options.deny_warnings)?; let main = context.get_main_function(&crate_id).ok_or_else(|| { // TODO(#2155): This error might be a better to exist in Nargo @@ -207,7 +192,7 @@ pub fn compile_contract( crate_id: CrateId, options: &CompileOptions, ) -> CompilationResult { - let (_, warnings) = check_crate(context, crate_id, options.deny_warnings, options.aztec_macro)?; + let (_, warnings) = check_crate(context, crate_id, options.deny_warnings)?; // TODO: We probably want to error if contracts is empty let contracts = context.get_all_contracts(&crate_id); diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index 52184a7f8e7..c1ae846f69a 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -157,7 +157,7 @@ pub fn compile( process_dependency_graph(&mut context, dependency_graph); - let compile_options = CompileOptions { aztec_macro: enable_aztec_macro, ..Default::default() }; + let compile_options = CompileOptions { ..Default::default() }; // For now we default to plonk width = 3, though we can add it as a parameter let np_language = acvm::Language::PLONKCSat { width: 3 }; diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index a449b497ede..aa981a735b5 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -46,21 +46,15 @@ pub struct LspState { root_path: Option, client: ClientSocket, solver: WrapperSolver, - enable_aztec_macro: bool, input_files: HashMap, } impl LspState { - fn new( - client: &ClientSocket, - solver: impl BlackBoxFunctionSolver + 'static, - enable_aztec_macro: bool, - ) -> Self { + fn new(client: &ClientSocket, solver: impl BlackBoxFunctionSolver + 'static) -> Self { Self { client: client.clone(), root_path: None, solver: WrapperSolver(Box::new(solver)), - enable_aztec_macro, input_files: HashMap::new(), } } @@ -71,12 +65,8 @@ pub struct NargoLspService { } impl NargoLspService { - pub fn new( - client: &ClientSocket, - solver: impl BlackBoxFunctionSolver + 'static, - enable_aztec_macro: bool, - ) -> Self { - let state = LspState::new(client, solver, enable_aztec_macro); + pub fn new(client: &ClientSocket, solver: impl BlackBoxFunctionSolver + 'static) -> Self { + let state = LspState::new(client, solver); let mut router = Router::new(state); router .request::(on_initialize) diff --git a/tooling/lsp/src/notifications/mod.rs b/tooling/lsp/src/notifications/mod.rs index b1c70b7e175..f6484f49d48 100644 --- a/tooling/lsp/src/notifications/mod.rs +++ b/tooling/lsp/src/notifications/mod.rs @@ -113,11 +113,10 @@ pub(super) fn on_did_save_text_document( .flat_map(|package| -> Vec { let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); - let file_diagnostics = - match check_crate(&mut context, crate_id, false, state.enable_aztec_macro) { - Ok(((), warnings)) => warnings, - Err(errors_and_warnings) => errors_and_warnings, - }; + let file_diagnostics = match check_crate(&mut context, crate_id, false) { + Ok(((), warnings)) => warnings, + Err(errors_and_warnings) => errors_and_warnings, + }; // We don't add test headings for a package if it contains no `#[test]` functions if let Some(tests) = get_package_tests_in_crate(&context, &crate_id, &package.name) { diff --git a/tooling/lsp/src/requests/code_lens_request.rs b/tooling/lsp/src/requests/code_lens_request.rs index 43577cb1126..602ed268981 100644 --- a/tooling/lsp/src/requests/code_lens_request.rs +++ b/tooling/lsp/src/requests/code_lens_request.rs @@ -86,7 +86,7 @@ fn on_code_lens_request_inner( let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation for producing code lenses // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, false, state.enable_aztec_macro); + let _ = check_crate(&mut context, crate_id, false); let fm = &context.file_manager; let files = fm.as_file_map(); diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index 8f4b6131c2f..4e615cd4fe5 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -56,7 +56,7 @@ fn on_goto_definition_inner( nargo::prepare_package(package, Box::new(crate::get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false, state.enable_aztec_macro); + let _ = noirc_driver::check_crate(&mut context, crate_id, false); let files = context.file_manager.as_file_map(); let file_id = context.file_manager.name_to_id(file_path.clone()); diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index c5bb18bf007..840678ddfc1 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -122,7 +122,7 @@ mod initialization { async fn test_on_initialize() { let client = ClientSocket::new_closed(); let solver = MockBackend; - let mut state = LspState::new(&client, solver, false); + let mut state = LspState::new(&client, solver); let params = InitializeParams::default(); let response = on_initialize(&mut state, params).await.unwrap(); assert!(matches!( diff --git a/tooling/lsp/src/requests/profile_run.rs b/tooling/lsp/src/requests/profile_run.rs index a648df8b65f..bd1cfeabe46 100644 --- a/tooling/lsp/src/requests/profile_run.rs +++ b/tooling/lsp/src/requests/profile_run.rs @@ -61,8 +61,7 @@ fn on_profile_run_request_inner( let is_opcode_supported = |_opcode: &Opcode| true; let np_language = Language::PLONKCSat { width: 3 }; - let compile_options = - CompileOptions { aztec_macro: state.enable_aztec_macro, ..Default::default() }; + let compile_options = CompileOptions { ..Default::default() }; let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace( &workspace, &binary_packages, diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index d7a61d315a8..962fe99a49b 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -52,7 +52,7 @@ fn on_test_run_request_inner( match workspace.into_iter().next() { Some(package) => { let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); - if check_crate(&mut context, crate_id, false, state.enable_aztec_macro).is_err() { + if check_crate(&mut context, crate_id, false).is_err() { let result = NargoTestRunResult { id: params.id.clone(), result: "error".to_string(), diff --git a/tooling/lsp/src/requests/tests.rs b/tooling/lsp/src/requests/tests.rs index f290e6ebb6e..6b94b921a06 100644 --- a/tooling/lsp/src/requests/tests.rs +++ b/tooling/lsp/src/requests/tests.rs @@ -56,7 +56,7 @@ fn on_tests_request_inner( let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation for producing tests // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, false, state.enable_aztec_macro); + let _ = check_crate(&mut context, crate_id, false); // We don't add test headings for a package if it contains no `#[test]` functions get_package_tests_in_crate(&context, &crate_id, &package.name) diff --git a/tooling/nargo_cli/src/cli/check_cmd.rs b/tooling/nargo_cli/src/cli/check_cmd.rs index 451cdc1c2cc..57b36b8932b 100644 --- a/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/tooling/nargo_cli/src/cli/check_cmd.rs @@ -62,7 +62,6 @@ fn check_package(package: &Package, compile_options: &CompileOptions) -> Result< crate_id, compile_options.deny_warnings, compile_options.silence_warnings, - compile_options.aztec_macro, )?; if package.is_library() || package.is_contract() { @@ -184,9 +183,8 @@ pub(crate) fn check_crate_and_report_errors( crate_id: CrateId, deny_warnings: bool, silence_warnings: bool, - enable_aztec_macro: bool, ) -> Result<(), CompileError> { - let result = check_crate(context, crate_id, deny_warnings, enable_aztec_macro); + let result = check_crate(context, crate_id, deny_warnings); super::compile_cmd::report_errors( result, &context.file_manager, diff --git a/tooling/nargo_cli/src/cli/lsp_cmd.rs b/tooling/nargo_cli/src/cli/lsp_cmd.rs index c274c5e941c..a41bb877991 100644 --- a/tooling/nargo_cli/src/cli/lsp_cmd.rs +++ b/tooling/nargo_cli/src/cli/lsp_cmd.rs @@ -4,7 +4,6 @@ use async_lsp::{ }; use clap::Args; use noir_lsp::NargoLspService; -use noirc_driver::is_aztec_environment_variable_set; use tower::ServiceBuilder; use super::NargoConfig; @@ -33,8 +32,7 @@ pub(crate) fn run( let (server, _) = async_lsp::MainLoop::new_server(|client| { #[allow(deprecated)] let blackbox_solver = barretenberg_blackbox_solver::BarretenbergSolver::new(); - let router = - NargoLspService::new(&client, blackbox_solver, is_aztec_environment_variable_set()); + let router = NargoLspService::new(&client, blackbox_solver); ServiceBuilder::new() .layer(TracingLayer::default()) diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index a391d8a3e8c..1b6dbcab34a 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -93,7 +93,6 @@ fn run_tests( crate_id, compile_options.deny_warnings, compile_options.silence_warnings, - compile_options.aztec_macro, )?; let test_functions = context.get_all_test_functions_in_crate_matching(&crate_id, fn_name); From cb69179bcffd21dfc0cb6215413e6c58583116b9 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Dec 2023 17:52:08 +0000 Subject: [PATCH 34/38] clippy --- compiler/noirc_driver/src/lib.rs | 3 +-- compiler/wasm/src/compile.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index bf1bafb834b..215d20288c7 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -122,8 +122,7 @@ pub fn check_crate( crate_id: CrateId, deny_warnings: bool, ) -> CompilationResult<()> { - let mut macros: Vec<&dyn MacroProcessor> = Vec::new(); - macros.push(&aztec_macros::AztecMacro as &dyn MacroProcessor); + let macros: Vec<&dyn MacroProcessor> = vec![&aztec_macros::AztecMacro as &dyn MacroProcessor]; let mut errors = vec![]; let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index c1ae846f69a..e0fec706b10 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -136,7 +136,6 @@ pub fn compile( entry_point: String, contracts: Option, dependency_graph: Option, - enable_aztec_macro: bool, ) -> Result { console_error_panic_hook::set_once(); From 97ed2fb3ddb003b2b2d97e9fb70fe34db972c6db Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Dec 2023 18:09:31 +0000 Subject: [PATCH 35/38] revert changes --- tooling/lsp/src/requests/profile_run.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tooling/lsp/src/requests/profile_run.rs b/tooling/lsp/src/requests/profile_run.rs index bd1cfeabe46..84888d30ba5 100644 --- a/tooling/lsp/src/requests/profile_run.rs +++ b/tooling/lsp/src/requests/profile_run.rs @@ -61,14 +61,13 @@ fn on_profile_run_request_inner( let is_opcode_supported = |_opcode: &Opcode| true; let np_language = Language::PLONKCSat { width: 3 }; - let compile_options = CompileOptions { ..Default::default() }; let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace( &workspace, &binary_packages, &contract_packages, np_language, is_opcode_supported, - &compile_options, + &CompileOptions::default(), ) .map_err(|err| ResponseError::new(ErrorCode::REQUEST_FAILED, err))?; From 9d0e9fdcd5373fafff946887c2e69c2dbf75c277 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Dec 2023 18:11:57 +0000 Subject: [PATCH 36/38] compile no longer needs extra parameter --- compiler/wasm/src/compile.rs | 2 +- compiler/wasm/test/node/index.test.ts | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index e0fec706b10..e7fd3dd5212 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -156,7 +156,7 @@ pub fn compile( process_dependency_graph(&mut context, dependency_graph); - let compile_options = CompileOptions { ..Default::default() }; + let compile_options = CompileOptions::default(); // For now we default to plonk width = 3, though we can add it as a parameter let np_language = acvm::Language::PLONKCSat { width: 3 }; diff --git a/compiler/wasm/test/node/index.test.ts b/compiler/wasm/test/node/index.test.ts index 4c9ce418cb8..c0d5f88e407 100644 --- a/compiler/wasm/test/node/index.test.ts +++ b/compiler/wasm/test/node/index.test.ts @@ -21,7 +21,7 @@ async function getPrecompiledSource(path: string): Promise { describe('noir wasm compilation', () => { describe('can compile simple scripts', () => { it('matching nargos compilation', async () => { - const wasmCircuit = await compile(join(__dirname, simpleScriptSourcePath), undefined, undefined, false); + const wasmCircuit = await compile(join(__dirname, simpleScriptSourcePath)); const cliCircuit = await getPrecompiledSource(simpleScriptExpectedArtifact); if (!('program' in wasmCircuit)) { @@ -56,17 +56,12 @@ describe('noir wasm compilation', () => { }); it('matching nargos compilation', async () => { - const wasmCircuit = await compile( - '/script/main.nr', - false, - { - root_dependencies: ['lib_a'], - library_dependencies: { - lib_a: ['lib_b'], - }, + const wasmCircuit = await compile('/script/main.nr', false, { + root_dependencies: ['lib_a'], + library_dependencies: { + lib_a: ['lib_b'], }, - false, - ); + }); const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); From 6c266dc8603119d320684af506946d39d5485301 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Dec 2023 19:10:49 +0000 Subject: [PATCH 37/38] add disable_macros flag --- compiler/noirc_driver/src/lib.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 215d20288c7..298e9838a09 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -61,6 +61,10 @@ pub struct CompileOptions { /// Suppress warnings #[arg(long, conflicts_with = "deny_warnings")] pub silence_warnings: bool, + + /// Disables the builtin macros being used in the compiler + #[arg(long, hide = true)] + pub disable_macros: bool, } /// Helper type used to signify where only warnings are expected in file diagnostics @@ -121,8 +125,13 @@ pub fn check_crate( context: &mut Context, crate_id: CrateId, deny_warnings: bool, + disable_macros: bool, ) -> CompilationResult<()> { - let macros: Vec<&dyn MacroProcessor> = vec![&aztec_macros::AztecMacro as &dyn MacroProcessor]; + let macros: Vec<&dyn MacroProcessor> = if disable_macros { + vec![] + } else { + vec![&aztec_macros::AztecMacro as &dyn MacroProcessor] + }; let mut errors = vec![]; let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); @@ -158,7 +167,8 @@ pub fn compile_main( cached_program: Option, force_compile: bool, ) -> CompilationResult { - let (_, mut warnings) = check_crate(context, crate_id, options.deny_warnings)?; + let (_, mut warnings) = + check_crate(context, crate_id, options.deny_warnings, options.disable_macros)?; let main = context.get_main_function(&crate_id).ok_or_else(|| { // TODO(#2155): This error might be a better to exist in Nargo @@ -191,7 +201,8 @@ pub fn compile_contract( crate_id: CrateId, options: &CompileOptions, ) -> CompilationResult { - let (_, warnings) = check_crate(context, crate_id, options.deny_warnings)?; + let (_, warnings) = + check_crate(context, crate_id, options.deny_warnings, options.disable_macros)?; // TODO: We probably want to error if contracts is empty let contracts = context.get_all_contracts(&crate_id); From 3bb1c2e229538deacf1b60766b0bc2d901d2f5b1 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Dec 2023 19:11:01 +0000 Subject: [PATCH 38/38] add code to handle disabling macros --- tooling/lsp/src/notifications/mod.rs | 2 +- tooling/lsp/src/requests/code_lens_request.rs | 2 +- tooling/lsp/src/requests/goto_definition.rs | 2 +- tooling/lsp/src/requests/test_run.rs | 2 +- tooling/lsp/src/requests/tests.rs | 2 +- tooling/nargo_cli/src/cli/check_cmd.rs | 4 +++- tooling/nargo_cli/src/cli/test_cmd.rs | 1 + 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tooling/lsp/src/notifications/mod.rs b/tooling/lsp/src/notifications/mod.rs index f6484f49d48..645d05d3d43 100644 --- a/tooling/lsp/src/notifications/mod.rs +++ b/tooling/lsp/src/notifications/mod.rs @@ -113,7 +113,7 @@ pub(super) fn on_did_save_text_document( .flat_map(|package| -> Vec { let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); - let file_diagnostics = match check_crate(&mut context, crate_id, false) { + let file_diagnostics = match check_crate(&mut context, crate_id, false, false) { Ok(((), warnings)) => warnings, Err(errors_and_warnings) => errors_and_warnings, }; diff --git a/tooling/lsp/src/requests/code_lens_request.rs b/tooling/lsp/src/requests/code_lens_request.rs index 602ed268981..a47e9f82a63 100644 --- a/tooling/lsp/src/requests/code_lens_request.rs +++ b/tooling/lsp/src/requests/code_lens_request.rs @@ -86,7 +86,7 @@ fn on_code_lens_request_inner( let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation for producing code lenses // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, false); + let _ = check_crate(&mut context, crate_id, false, false); let fm = &context.file_manager; let files = fm.as_file_map(); diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index 4e615cd4fe5..4b5ccddc613 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -56,7 +56,7 @@ fn on_goto_definition_inner( nargo::prepare_package(package, Box::new(crate::get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation while resolving the definition - let _ = noirc_driver::check_crate(&mut context, crate_id, false); + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false); let files = context.file_manager.as_file_map(); let file_id = context.file_manager.name_to_id(file_path.clone()); diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index 962fe99a49b..293b101eb85 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -52,7 +52,7 @@ fn on_test_run_request_inner( match workspace.into_iter().next() { Some(package) => { let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); - if check_crate(&mut context, crate_id, false).is_err() { + if check_crate(&mut context, crate_id, false, false).is_err() { let result = NargoTestRunResult { id: params.id.clone(), result: "error".to_string(), diff --git a/tooling/lsp/src/requests/tests.rs b/tooling/lsp/src/requests/tests.rs index 6b94b921a06..bed29ebe4e6 100644 --- a/tooling/lsp/src/requests/tests.rs +++ b/tooling/lsp/src/requests/tests.rs @@ -56,7 +56,7 @@ fn on_tests_request_inner( let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); // We ignore the warnings and errors produced by compilation for producing tests // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, false); + let _ = check_crate(&mut context, crate_id, false, false); // We don't add test headings for a package if it contains no `#[test]` functions get_package_tests_in_crate(&context, &crate_id, &package.name) diff --git a/tooling/nargo_cli/src/cli/check_cmd.rs b/tooling/nargo_cli/src/cli/check_cmd.rs index 57b36b8932b..20e51fe1b52 100644 --- a/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/tooling/nargo_cli/src/cli/check_cmd.rs @@ -61,6 +61,7 @@ fn check_package(package: &Package, compile_options: &CompileOptions) -> Result< &mut context, crate_id, compile_options.deny_warnings, + compile_options.disable_macros, compile_options.silence_warnings, )?; @@ -182,9 +183,10 @@ pub(crate) fn check_crate_and_report_errors( context: &mut Context, crate_id: CrateId, deny_warnings: bool, + disable_macros: bool, silence_warnings: bool, ) -> Result<(), CompileError> { - let result = check_crate(context, crate_id, deny_warnings); + let result = check_crate(context, crate_id, deny_warnings, disable_macros); super::compile_cmd::report_errors( result, &context.file_manager, diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index 1b6dbcab34a..7f7ae67d946 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -92,6 +92,7 @@ fn run_tests( &mut context, crate_id, compile_options.deny_warnings, + compile_options.disable_macros, compile_options.silence_warnings, )?;