diff --git a/compiler/fm/src/file_map.rs b/compiler/fm/src/file_map.rs index 0cbdc535e40..c4d7002a082 100644 --- a/compiler/fm/src/file_map.rs +++ b/compiler/fm/src/file_map.rs @@ -30,7 +30,7 @@ impl From<&PathBuf> for PathString { PathString::from(pb.to_owned()) } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FileMap { files: SimpleFiles, name_to_id: HashMap, diff --git a/compiler/fm/src/lib.rs b/compiler/fm/src/lib.rs index 4870a6c283b..55fb762479f 100644 --- a/compiler/fm/src/lib.rs +++ b/compiler/fm/src/lib.rs @@ -16,7 +16,7 @@ use std::{ }; pub const FILE_EXTENSION: &str = "nr"; - +#[derive(Clone)] pub struct FileManager { root: PathBuf, file_map: FileMap, diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 24b159568f2..926e541c2f3 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -4,7 +4,7 @@ #![warn(clippy::semicolon_if_nothing_returned)] use clap::Args; -use fm::FileId; +use fm::{FileId, FileManager}; use iter_extended::vecmap; use noirc_abi::{AbiParameter, AbiType, ContractEvent}; use noirc_errors::{CustomDiagnostic, FileDiagnostic}; @@ -81,17 +81,36 @@ pub type ErrorsAndWarnings = Vec; /// Helper type for connecting a compilation artifact to the errors or warnings which were produced during compilation. pub type CompilationResult = Result<(T, Warnings), ErrorsAndWarnings>; -/// Adds the file from the file system at `Path` to the crate graph as a root file -pub fn prepare_crate(context: &mut Context, file_name: &Path) -> CrateId { +/// Helper method to return a file manager instance with the stdlib already added +/// +/// TODO: This should become the canonical way to create a file manager and +/// TODO if we use a File manager trait, we can move file manager into this crate +/// TODO as a module +pub fn file_manager_with_stdlib(root: &Path) -> FileManager { + let mut file_manager = FileManager::new(root); + + add_stdlib_source_to_file_manager(&mut file_manager); + + file_manager +} + +/// Adds the source code for the stdlib into the file manager +fn add_stdlib_source_to_file_manager(file_manager: &mut FileManager) { // Add the stdlib contents to the file manager, since every package automatically has a dependency // on the stdlib. For other dependencies, we read the package.Dependencies file to add their file // contents to the file manager. However since the dependency on the stdlib is implicit, we need // to manually add it here. let stdlib_paths_with_source = stdlib::stdlib_paths_with_source(); for (path, source) in stdlib_paths_with_source { - context.file_manager.add_file_with_source_canonical_path(Path::new(&path), source); + file_manager.add_file_with_source_canonical_path(Path::new(&path), source); } +} +/// Adds the file from the file system at `Path` to the crate graph as a root file +/// +/// Note: This methods adds the stdlib as a dependency to the crate. +/// This assumes that the stdlib has already been added to the file manager. +pub fn prepare_crate(context: &mut Context, file_name: &Path) -> CrateId { let path_to_std_lib_file = Path::new(STD_CRATE_NAME).join("lib.nr"); let std_file_id = context .file_manager diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index adeca7cf2ba..25875385fd9 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -10,6 +10,7 @@ use crate::node_interner::{FuncId, NodeInterner, StructId}; use def_map::{Contract, CrateDefMap}; use fm::FileManager; use noirc_errors::Location; +use std::borrow::Cow; use std::collections::BTreeMap; use self::def_map::TestFunction; @@ -17,11 +18,14 @@ use self::def_map::TestFunction; /// Helper object which groups together several useful context objects used /// during name resolution. Once name resolution is finished, only the /// def_interner is required for type inference and monomorphization. -pub struct Context { +pub struct Context<'file_manager> { pub def_interner: NodeInterner, pub crate_graph: CrateGraph, pub(crate) def_maps: BTreeMap, - pub file_manager: FileManager, + // In the WASM context, we take ownership of the file manager, + // which is why this needs to be a Cow. In all use-cases, the file manager + // is read-only however, once it has been passed to the Context. + pub file_manager: Cow<'file_manager, FileManager>, /// A map of each file that already has been visited from a prior `mod foo;` declaration. /// This is used to issue an error if a second `mod foo;` is declared to the same file. @@ -35,15 +39,24 @@ pub enum FunctionNameMatch<'a> { Contains(&'a str), } -impl Context { - pub fn new(file_manager: FileManager) -> Context { - let crate_graph = CrateGraph::default(); +impl Context<'_> { + pub fn new(file_manager: FileManager) -> Context<'static> { Context { def_interner: NodeInterner::default(), def_maps: BTreeMap::new(), visited_files: BTreeMap::new(), - crate_graph, - file_manager, + crate_graph: CrateGraph::default(), + file_manager: Cow::Owned(file_manager), + } + } + + pub fn from_ref_file_manager(file_manager: &FileManager) -> Context<'_> { + Context { + def_interner: NodeInterner::default(), + def_maps: BTreeMap::new(), + visited_files: BTreeMap::new(), + crate_graph: CrateGraph::default(), + file_manager: Cow::Borrowed(file_manager), } } diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index 4012effd947..c6ae0ae1f42 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -7,8 +7,9 @@ use nargo::artifacts::{ program::PreprocessedProgram, }; use noirc_driver::{ - add_dep, compile_contract, compile_main, prepare_crate, prepare_dependency, CompileOptions, - CompiledContract, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, + add_dep, compile_contract, compile_main, file_manager_with_stdlib, prepare_crate, + prepare_dependency, CompileOptions, CompiledContract, CompiledProgram, + NOIR_ARTIFACT_VERSION_STRING, }; use noirc_frontend::{ graph::{CrateId, CrateName}, @@ -224,7 +225,7 @@ pub fn compile( // should be considered as immutable. pub(crate) fn file_manager_with_source_map(source_map: PathToFileSourceMap) -> FileManager { let root = Path::new(""); - let mut fm = FileManager::new(root); + let mut fm = file_manager_with_stdlib(root); for (path, source) in source_map.0 { fm.add_file_with_source(path.as_path(), source); @@ -327,7 +328,7 @@ mod test { use super::{file_manager_with_source_map, process_dependency_graph, DependencyGraph}; use std::{collections::HashMap, path::Path}; - fn setup_test_context(source_map: PathToFileSourceMap) -> Context { + fn setup_test_context(source_map: PathToFileSourceMap) -> Context<'static> { let mut fm = file_manager_with_source_map(source_map); // Add this due to us calling prepare_crate on "/main.nr" below fm.add_file_with_source(Path::new("/main.nr"), "fn foo() {}".to_string()); diff --git a/compiler/wasm/src/compile_new.rs b/compiler/wasm/src/compile_new.rs index cd09d0fcc49..0cd1a2c50e5 100644 --- a/compiler/wasm/src/compile_new.rs +++ b/compiler/wasm/src/compile_new.rs @@ -18,7 +18,9 @@ use wasm_bindgen::prelude::wasm_bindgen; /// then the impl block is not picked up in javascript. #[wasm_bindgen] pub struct CompilerContext { - context: Context, + // `wasm_bindgen` currently doesn't allow lifetime parameters on structs so we must use a `'static` lifetime. + // `Context` must then own the `FileManager` to satisfy this lifetime. + context: Context<'static>, } #[wasm_bindgen(js_name = "CrateId")] diff --git a/tooling/lsp/src/notifications/mod.rs b/tooling/lsp/src/notifications/mod.rs index 61f0d231738..d0ca8679e7e 100644 --- a/tooling/lsp/src/notifications/mod.rs +++ b/tooling/lsp/src/notifications/mod.rs @@ -1,9 +1,9 @@ use std::ops::ControlFlow; use async_lsp::{ErrorCode, LanguageClient, ResponseError}; -use nargo::prepare_package; +use nargo::{insert_all_files_for_workspace_into_file_manager, prepare_package}; use nargo_toml::{find_file_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{check_crate, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{check_crate, file_manager_with_stdlib, NOIR_ARTIFACT_VERSION_STRING}; use noirc_errors::{DiagnosticKind, FileDiagnostic}; use crate::types::{ @@ -100,10 +100,13 @@ pub(super) fn on_did_save_text_document( } }; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let diagnostics: Vec<_> = workspace .into_iter() .flat_map(|package| -> Vec { - let (mut context, crate_id) = prepare_package(package); + let (mut context, crate_id) = prepare_package(&workspace_file_manager, package); let file_diagnostics = match check_crate(&mut context, crate_id, false, false) { Ok(((), warnings)) => warnings, diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index 558851d4ecf..a23bde2e210 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -5,8 +5,9 @@ use async_lsp::{ErrorCode, LanguageClient, ResponseError}; use fm::codespan_files::Error; use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse, Location}; use lsp_types::{Position, Url}; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; +use noirc_driver::{file_manager_with_stdlib, NOIR_ARTIFACT_VERSION_STRING}; pub(crate) fn on_goto_definition_request( state: &mut LspState, @@ -51,8 +52,11 @@ fn on_goto_definition_inner( let mut definition_position = None; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + for package in &workspace { - let (mut context, crate_id) = nargo::prepare_package(package); + let (mut context, crate_id) = nargo::prepare_package(&workspace_file_manager, package); // We ignore the warnings and errors produced by compilation while resolving the definition let _ = noirc_driver::check_crate(&mut context, crate_id, false, false); diff --git a/tooling/lsp/src/requests/profile_run.rs b/tooling/lsp/src/requests/profile_run.rs index 4c4d7f11fde..6664475a68c 100644 --- a/tooling/lsp/src/requests/profile_run.rs +++ b/tooling/lsp/src/requests/profile_run.rs @@ -5,9 +5,11 @@ use std::{ use acvm::ExpressionWidth; use async_lsp::{ErrorCode, ResponseError}; -use nargo::artifacts::debug::DebugArtifact; +use nargo::{artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager}; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{CompileOptions, DebugFile, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{ + file_manager_with_stdlib, CompileOptions, DebugFile, NOIR_ARTIFACT_VERSION_STRING, +}; use noirc_errors::{debug_info::OpCodesCount, Location}; use crate::{ @@ -48,6 +50,9 @@ fn on_profile_run_request_inner( ResponseError::new(ErrorCode::REQUEST_FAILED, err) })?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + // Since we filtered on crate name, this should be the only item in the iterator match workspace.into_iter().next() { Some(_package) => { @@ -60,6 +65,7 @@ fn on_profile_run_request_inner( let expression_width = ExpressionWidth::Bounded { width: 3 }; let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace( + &workspace_file_manager, &workspace, &binary_packages, &contract_packages, diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index e5245de426f..2a040a2e3e9 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -2,11 +2,14 @@ use std::future::{self, Future}; use async_lsp::{ErrorCode, ResponseError}; use nargo::{ + insert_all_files_for_workspace_into_file_manager, ops::{run_test, TestStatus}, prepare_package, }; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{check_crate, CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{ + check_crate, file_manager_with_stdlib, CompileOptions, NOIR_ARTIFACT_VERSION_STRING, +}; use noirc_frontend::hir::FunctionNameMatch; use crate::{ @@ -47,10 +50,13 @@ fn on_test_run_request_inner( ResponseError::new(ErrorCode::REQUEST_FAILED, err) })?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + // Since we filtered on crate name, this should be the only item in the iterator match workspace.into_iter().next() { Some(package) => { - let (mut context, crate_id) = prepare_package(package); + let (mut context, crate_id) = prepare_package(&workspace_file_manager, package); if check_crate(&mut context, crate_id, false, false).is_err() { let result = NargoTestRunResult { id: params.id.clone(), diff --git a/tooling/lsp/src/requests/tests.rs b/tooling/lsp/src/requests/tests.rs index 9a67eaae6db..0f717b9fb9e 100644 --- a/tooling/lsp/src/requests/tests.rs +++ b/tooling/lsp/src/requests/tests.rs @@ -2,9 +2,9 @@ use std::future::{self, Future}; use async_lsp::{ErrorCode, LanguageClient, ResponseError}; use lsp_types::{LogMessageParams, MessageType}; -use nargo::prepare_package; +use nargo::{insert_all_files_for_workspace_into_file_manager, prepare_package}; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{check_crate, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{check_crate, file_manager_with_stdlib, NOIR_ARTIFACT_VERSION_STRING}; use crate::{ get_package_tests_in_crate, @@ -50,10 +50,13 @@ fn on_tests_request_inner( ResponseError::new(ErrorCode::REQUEST_FAILED, err) })?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let package_tests: Vec<_> = workspace .into_iter() .filter_map(|package| { - let (mut context, crate_id) = prepare_package(package); + let (mut context, crate_id) = prepare_package(&workspace_file_manager, package); // 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, false); diff --git a/tooling/nargo/src/lib.rs b/tooling/nargo/src/lib.rs index f0c7277060f..db54fd3d574 100644 --- a/tooling/nargo/src/lib.rs +++ b/tooling/nargo/src/lib.rs @@ -42,13 +42,21 @@ pub fn prepare_dependencies( } } +pub fn insert_all_files_for_workspace_into_file_manager( + workspace: &workspace::Workspace, + file_manager: &mut FileManager, +) { + for package in workspace.clone().into_iter() { + insert_all_files_for_package_into_file_manager(package, file_manager); + } +} // We will pre-populate the file manager with all the files in the package // This is so that we can avoid having to read from disk when we are compiling // // This does not require parsing because we are interested in the files under the src directory // it may turn out that we do not need to include some Noir files that we add to the file // manager -pub fn insert_all_files_for_package_into_file_manager( +fn insert_all_files_for_package_into_file_manager( package: &Package, file_manager: &mut FileManager, ) { @@ -87,11 +95,11 @@ fn insert_all_files_for_packages_dependencies_into_file_manager( } } -pub fn prepare_package(package: &Package) -> (Context, CrateId) { - let mut fm = FileManager::new(&package.root_dir); - insert_all_files_for_package_into_file_manager(package, &mut fm); - - let mut context = Context::new(fm); +pub fn prepare_package<'file_manager>( + file_manager: &'file_manager FileManager, + package: &Package, +) -> (Context<'file_manager>, CrateId) { + let mut context = Context::from_ref_file_manager(file_manager); let crate_id = prepare_crate(&mut context, &package.entry_path); diff --git a/tooling/nargo/src/ops/compile.rs b/tooling/nargo/src/ops/compile.rs index 1a9e0a6c115..bd395d03f67 100644 --- a/tooling/nargo/src/ops/compile.rs +++ b/tooling/nargo/src/ops/compile.rs @@ -14,6 +14,7 @@ use rayon::prelude::*; /// /// This function will return an error if there are any compilations errors reported. pub fn compile_workspace( + file_manager: &FileManager, workspace: &Workspace, binary_packages: &[Package], contract_packages: &[Package], @@ -21,23 +22,24 @@ pub fn compile_workspace( compile_options: &CompileOptions, ) -> Result<(Vec, Vec), CompileError> { // Compile all of the packages in parallel. - let program_results: Vec<(FileManager, CompilationResult)> = binary_packages + let program_results: Vec> = binary_packages + .par_iter() + .map(|package| { + compile_program(file_manager, workspace, package, compile_options, expression_width) + }) + .collect(); + let contract_results: Vec> = contract_packages .par_iter() - .map(|package| compile_program(workspace, package, compile_options, expression_width)) + .map(|package| compile_contract(file_manager, package, compile_options, expression_width)) .collect(); - let contract_results: Vec<(FileManager, CompilationResult)> = - contract_packages - .par_iter() - .map(|package| compile_contract(package, compile_options, expression_width)) - .collect(); // Report any warnings/errors which were encountered during compilation. let compiled_programs: Vec = program_results .into_iter() - .map(|(file_manager, compilation_result)| { + .map(|compilation_result| { report_errors( compilation_result, - &file_manager, + file_manager, compile_options.deny_warnings, compile_options.silence_warnings, ) @@ -45,10 +47,10 @@ pub fn compile_workspace( .collect::>()?; let compiled_contracts: Vec = contract_results .into_iter() - .map(|(file_manager, compilation_result)| { + .map(|compilation_result| { report_errors( compilation_result, - &file_manager, + file_manager, compile_options.deny_warnings, compile_options.silence_warnings, ) @@ -59,12 +61,13 @@ pub fn compile_workspace( } pub fn compile_program( + file_manager: &FileManager, workspace: &Workspace, package: &Package, compile_options: &CompileOptions, expression_width: ExpressionWidth, -) -> (FileManager, CompilationResult) { - let (mut context, crate_id) = prepare_package(package); +) -> CompilationResult { + let (mut context, crate_id) = prepare_package(file_manager, package); let program_artifact_path = workspace.package_build_path(package); let mut debug_artifact_path = program_artifact_path.clone(); @@ -74,33 +77,34 @@ pub fn compile_program( match noirc_driver::compile_main(&mut context, crate_id, compile_options, None, true) { Ok(program_and_warnings) => program_and_warnings, Err(errors) => { - return (context.file_manager, Err(errors)); + return Err(errors); } }; // Apply backend specific optimizations. let optimized_program = crate::ops::optimize_program(program, expression_width); - (context.file_manager, Ok((optimized_program, warnings))) + Ok((optimized_program, warnings)) } fn compile_contract( + file_manager: &FileManager, package: &Package, compile_options: &CompileOptions, expression_width: ExpressionWidth, -) -> (FileManager, CompilationResult) { - let (mut context, crate_id) = prepare_package(package); +) -> CompilationResult { + let (mut context, crate_id) = prepare_package(file_manager, package); let (contract, warnings) = match noirc_driver::compile_contract(&mut context, crate_id, compile_options) { Ok(contracts_and_warnings) => contracts_and_warnings, Err(errors) => { - return (context.file_manager, Err(errors)); + return Err(errors); } }; let optimized_contract = crate::ops::optimize_contract(contract, expression_width); - (context.file_manager, Ok((optimized_contract, warnings))) + Ok((optimized_contract, warnings)) } pub(crate) fn report_errors( diff --git a/tooling/nargo_cli/src/cli/check_cmd.rs b/tooling/nargo_cli/src/cli/check_cmd.rs index 0ea8186a237..e2db492fe9c 100644 --- a/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/tooling/nargo_cli/src/cli/check_cmd.rs @@ -2,12 +2,17 @@ use crate::backends::Backend; use crate::errors::CliError; use clap::Args; +use fm::FileManager; use iter_extended::btree_map; -use nargo::{errors::CompileError, package::Package, prepare_package}; +use nargo::{ + errors::CompileError, insert_all_files_for_workspace_into_file_manager, package::Package, + prepare_package, +}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::{AbiParameter, AbiType, MAIN_RETURN_NAME}; use noirc_driver::{ - check_crate, compute_function_abi, CompileOptions, NOIR_ARTIFACT_VERSION_STRING, + check_crate, compute_function_abi, file_manager_with_stdlib, CompileOptions, + NOIR_ARTIFACT_VERSION_STRING, }; use noirc_frontend::{ graph::{CrateId, CrateName}, @@ -47,15 +52,22 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + for package in &workspace { - check_package(package, &args.compile_options)?; + check_package(&workspace_file_manager, package, &args.compile_options)?; println!("[{}] Constraint system successfully built!", package.name); } Ok(()) } -fn check_package(package: &Package, compile_options: &CompileOptions) -> Result<(), CompileError> { - let (mut context, crate_id) = prepare_package(package); +fn check_package( + file_manager: &FileManager, + package: &Package, + compile_options: &CompileOptions, +) -> Result<(), CompileError> { + let (mut context, crate_id) = prepare_package(file_manager, package); check_crate_and_report_errors( &mut context, crate_id, diff --git a/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs index b72ce01e1a9..fe79c0b8c23 100644 --- a/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -9,10 +9,12 @@ use crate::errors::CliError; use acvm::ExpressionWidth; use bb_abstraction_leaks::ACVM_BACKEND_BARRETENBERG; use clap::Args; +use fm::FileManager; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo::package::Package; use nargo::workspace::Workspace; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{file_manager_with_stdlib, CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; use noirc_frontend::graph::CrateName; /// Generates a Solidity verifier smart contract for the program @@ -45,9 +47,13 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let expression_width = backend.get_backend_info()?; for package in &workspace { let smart_contract_string = smart_contract_for_package( + &workspace_file_manager, &workspace, backend, package, @@ -67,13 +73,15 @@ pub(crate) fn run( } fn smart_contract_for_package( + file_manager: &FileManager, workspace: &Workspace, backend: &Backend, package: &Package, compile_options: &CompileOptions, expression_width: ExpressionWidth, ) -> Result { - let program = compile_bin_package(workspace, package, compile_options, expression_width)?; + let program = + compile_bin_package(file_manager, workspace, package, compile_options, expression_width)?; let mut smart_contract_string = backend.eth_contract(&program.circuit)?; diff --git a/tooling/nargo_cli/src/cli/compile_cmd.rs b/tooling/nargo_cli/src/cli/compile_cmd.rs index 5ee053c5088..661081778c3 100644 --- a/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -8,10 +8,12 @@ use nargo::artifacts::contract::PreprocessedContractFunction; use nargo::artifacts::debug::DebugArtifact; use nargo::artifacts::program::PreprocessedProgram; use nargo::errors::CompileError; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo::package::Package; use nargo::prepare_package; use nargo::workspace::Workspace; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; +use noirc_driver::file_manager_with_stdlib; use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram}; use noirc_frontend::graph::CrateName; @@ -61,6 +63,9 @@ pub(crate) fn run( )?; let circuit_dir = workspace.target_directory_path(); + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace .into_iter() .filter(|package| !package.is_library()) @@ -69,6 +74,7 @@ pub(crate) fn run( let expression_width = backend.get_backend_info_or_default(); let (_, compiled_contracts) = compile_workspace( + &workspace_file_manager, &workspace, &binary_packages, &contract_packages, @@ -85,6 +91,7 @@ pub(crate) fn run( } pub(super) fn compile_workspace( + file_manager: &FileManager, workspace: &Workspace, binary_packages: &[Package], contract_packages: &[Package], @@ -92,23 +99,24 @@ pub(super) fn compile_workspace( compile_options: &CompileOptions, ) -> Result<(Vec, Vec), CliError> { // Compile all of the packages in parallel. - let program_results: Vec<(FileManager, CompilationResult)> = binary_packages + let program_results: Vec> = binary_packages + .par_iter() + .map(|package| { + compile_program(file_manager, workspace, package, compile_options, expression_width) + }) + .collect(); + let contract_results: Vec> = contract_packages .par_iter() - .map(|package| compile_program(workspace, package, compile_options, expression_width)) + .map(|package| compile_contract(file_manager, package, compile_options, expression_width)) .collect(); - let contract_results: Vec<(FileManager, CompilationResult)> = - contract_packages - .par_iter() - .map(|package| compile_contract(package, compile_options, expression_width)) - .collect(); // Report any warnings/errors which were encountered during compilation. let compiled_programs: Vec = program_results .into_iter() - .map(|(file_manager, compilation_result)| { + .map(|compilation_result| { report_errors( compilation_result, - &file_manager, + file_manager, compile_options.deny_warnings, compile_options.silence_warnings, ) @@ -116,10 +124,10 @@ pub(super) fn compile_workspace( .collect::>()?; let compiled_contracts: Vec = contract_results .into_iter() - .map(|(file_manager, compilation_result)| { + .map(|compilation_result| { report_errors( compilation_result, - &file_manager, + file_manager, compile_options.deny_warnings, compile_options.silence_warnings, ) @@ -130,6 +138,7 @@ pub(super) fn compile_workspace( } pub(crate) fn compile_bin_package( + file_manager: &FileManager, workspace: &Workspace, package: &Package, compile_options: &CompileOptions, @@ -139,12 +148,12 @@ pub(crate) fn compile_bin_package( return Err(CompileError::LibraryCrate(package.name.clone()).into()); } - let (file_manager, compilation_result) = - compile_program(workspace, package, compile_options, expression_width); + let compilation_result = + compile_program(file_manager, workspace, package, compile_options, expression_width); let program = report_errors( compilation_result, - &file_manager, + file_manager, compile_options.deny_warnings, compile_options.silence_warnings, )?; @@ -153,12 +162,13 @@ pub(crate) fn compile_bin_package( } fn compile_program( + file_manager: &FileManager, workspace: &Workspace, package: &Package, compile_options: &CompileOptions, expression_width: ExpressionWidth, -) -> (FileManager, CompilationResult) { - let (mut context, crate_id) = prepare_package(package); +) -> CompilationResult { + let (mut context, crate_id) = prepare_package(file_manager, package); let program_artifact_path = workspace.package_build_path(package); let mut debug_artifact_path = program_artifact_path.clone(); @@ -191,7 +201,7 @@ fn compile_program( ) { Ok(program_and_warnings) => program_and_warnings, Err(errors) => { - return (context.file_manager, Err(errors)); + return Err(errors); } }; @@ -200,26 +210,27 @@ fn compile_program( let only_acir = compile_options.only_acir; save_program(optimized_program.clone(), package, &workspace.target_directory_path(), only_acir); - (context.file_manager, Ok((optimized_program, warnings))) + Ok((optimized_program, warnings)) } fn compile_contract( + file_manager: &FileManager, package: &Package, compile_options: &CompileOptions, expression_width: ExpressionWidth, -) -> (FileManager, CompilationResult) { - let (mut context, crate_id) = prepare_package(package); +) -> CompilationResult { + let (mut context, crate_id) = prepare_package(file_manager, package); let (contract, warnings) = match noirc_driver::compile_contract(&mut context, crate_id, compile_options) { Ok(contracts_and_warnings) => contracts_and_warnings, Err(errors) => { - return (context.file_manager, Err(errors)); + return Err(errors); } }; let optimized_contract = nargo::ops::optimize_contract(contract, expression_width); - (context.file_manager, Ok((optimized_contract, warnings))) + Ok((optimized_contract, warnings)) } fn save_program( diff --git a/tooling/nargo_cli/src/cli/debug_cmd.rs b/tooling/nargo_cli/src/cli/debug_cmd.rs index 6eab626a08d..e603dfc5492 100644 --- a/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -5,11 +5,14 @@ use clap::Args; use nargo::artifacts::debug::DebugArtifact; use nargo::constants::PROVER_INPUT_FILE; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo::package::Package; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::input_parser::{Format, InputValue}; use noirc_abi::InputMap; -use noirc_driver::{CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{ + file_manager_with_stdlib, CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, +}; use noirc_frontend::graph::CrateName; use super::compile_cmd::compile_bin_package; @@ -51,6 +54,9 @@ pub(crate) fn run( let target_dir = &workspace.target_directory_path(); let expression_width = backend.get_backend_info()?; + let mut workspace_file_manager = file_manager_with_stdlib(std::path::Path::new("")); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let Some(package) = workspace.into_iter().find(|p| p.is_binary()) else { println!( "No matching binary packages found in workspace. Only binary packages can be debugged." @@ -58,8 +64,13 @@ pub(crate) fn run( return Ok(()); }; - let compiled_program = - compile_bin_package(&workspace, package, &args.compile_options, expression_width)?; + let compiled_program = compile_bin_package( + &workspace_file_manager, + &workspace, + package, + &args.compile_options, + expression_width, + )?; run_async(package, compiled_program, &args.prover_name, &args.witness_name, target_dir) } diff --git a/tooling/nargo_cli/src/cli/execute_cmd.rs b/tooling/nargo_cli/src/cli/execute_cmd.rs index 10760f43a45..3d7af2ec4e5 100644 --- a/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -4,12 +4,15 @@ use clap::Args; use nargo::artifacts::debug::DebugArtifact; use nargo::constants::PROVER_INPUT_FILE; use nargo::errors::try_to_diagnose_runtime_error; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo::ops::DefaultForeignCallExecutor; use nargo::package::Package; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::input_parser::{Format, InputValue}; use noirc_abi::InputMap; -use noirc_driver::{CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{ + file_manager_with_stdlib, CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, +}; use noirc_frontend::graph::CrateName; use super::compile_cmd::compile_bin_package; @@ -56,10 +59,18 @@ pub(crate) fn run( )?; let target_dir = &workspace.target_directory_path(); + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let expression_width = backend.get_backend_info_or_default(); for package in &workspace { - let compiled_program = - compile_bin_package(&workspace, package, &args.compile_options, expression_width)?; + let compiled_program = compile_bin_package( + &workspace_file_manager, + &workspace, + package, + &args.compile_options, + expression_width, + )?; let (return_value, solved_witness) = execute_program_and_decode(compiled_program, package, &args.prover_name)?; diff --git a/tooling/nargo_cli/src/cli/fmt_cmd.rs b/tooling/nargo_cli/src/cli/fmt_cmd.rs index e62fc560217..78678559547 100644 --- a/tooling/nargo_cli/src/cli/fmt_cmd.rs +++ b/tooling/nargo_cli/src/cli/fmt_cmd.rs @@ -1,10 +1,9 @@ use std::{fs::DirEntry, path::Path}; use clap::Args; -use fm::FileManager; -use nargo::insert_all_files_for_package_into_file_manager; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; +use noirc_driver::{file_manager_with_stdlib, NOIR_ARTIFACT_VERSION_STRING}; use noirc_errors::CustomDiagnostic; use noirc_frontend::{hir::def_map::parse_file, parser::ParserError}; @@ -30,18 +29,18 @@ pub(crate) fn run(args: FormatCommand, config: NargoConfig) -> Result<(), CliErr Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let config = nargo_fmt::Config::read(&config.program_dir) .map_err(|err| CliError::Generic(err.to_string()))?; let mut check_exit_code_one = false; for package in &workspace { - let mut file_manager = FileManager::new(&package.root_dir); - insert_all_files_for_package_into_file_manager(package, &mut file_manager); - visit_noir_files(&package.root_dir.join("src"), &mut |entry| { - let file_id = file_manager.name_to_id(entry.path().to_path_buf()).expect("The file should exist since we added all files in the package into the file manager"); - let (parsed_module, errors) = parse_file(&file_manager, file_id); + let file_id = workspace_file_manager.name_to_id(entry.path().to_path_buf()).expect("The file should exist since we added all files in the package into the file manager"); + let (parsed_module, errors) = parse_file(&workspace_file_manager, file_id); let is_all_warnings = errors.iter().all(ParserError::is_warning); if !is_all_warnings { @@ -55,14 +54,14 @@ pub(crate) fn run(args: FormatCommand, config: NargoConfig) -> Result<(), CliErr let _ = super::compile_cmd::report_errors::<()>( Err(errors), - &file_manager, + &workspace_file_manager, false, false, ); return Ok(()); } - let original = file_manager.fetch_file(file_id); + let original = workspace_file_manager.fetch_file(file_id); let formatted = nargo_fmt::format(original, parsed_module, &config); if check_mode { diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index e25051c1df7..f983a19c0fd 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -4,10 +4,14 @@ use acvm::ExpressionWidth; use backend_interface::BackendError; use clap::Args; use iter_extended::vecmap; -use nargo::{artifacts::debug::DebugArtifact, package::Package}; +use nargo::{ + artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager, + package::Package, +}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{ - CompileOptions, CompiledContract, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, + file_manager_with_stdlib, CompileOptions, CompiledContract, CompiledProgram, + NOIR_ARTIFACT_VERSION_STRING, }; use noirc_errors::{debug_info::OpCodesCount, Location}; use noirc_frontend::graph::CrateName; @@ -61,6 +65,9 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace .into_iter() .filter(|package| !package.is_library()) @@ -69,6 +76,7 @@ pub(crate) fn run( let expression_width = backend.get_backend_info_or_default(); let (compiled_programs, compiled_contracts) = compile_workspace( + &workspace_file_manager, &workspace, &binary_packages, &contract_packages, diff --git a/tooling/nargo_cli/src/cli/prove_cmd.rs b/tooling/nargo_cli/src/cli/prove_cmd.rs index cb1751e7cef..2b1dd8c65f3 100644 --- a/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -1,10 +1,13 @@ use clap::Args; use nargo::constants::{PROVER_INPUT_FILE, VERIFIER_INPUT_FILE}; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo::package::Package; use nargo::workspace::Workspace; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::input_parser::Format; -use noirc_driver::{CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{ + file_manager_with_stdlib, CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, +}; use noirc_frontend::graph::CrateName; use super::compile_cmd::compile_bin_package; @@ -57,10 +60,18 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let expression_width = backend.get_backend_info()?; for package in &workspace { - let program = - compile_bin_package(&workspace, package, &args.compile_options, expression_width)?; + let program = compile_bin_package( + &workspace_file_manager, + &workspace, + package, + &args.compile_options, + expression_width, + )?; prove_package( backend, diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index fcad4d4ee9f..809994219cb 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -2,13 +2,15 @@ use std::io::Write; use acvm::BlackBoxFunctionSolver; use clap::Args; +use fm::FileManager; use nargo::{ + insert_all_files_for_workspace_into_file_manager, ops::{run_test, TestStatus}, package::Package, prepare_package, }; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{file_manager_with_stdlib, CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; use noirc_frontend::{graph::CrateName, hir::FunctionNameMatch}; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; @@ -57,6 +59,9 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let pattern = match &args.test_name { Some(name) => { if args.exact { @@ -73,20 +78,28 @@ pub(crate) fn run( for package in &workspace { // By unwrapping here with `?`, we stop the test runner upon a package failing // TODO: We should run the whole suite even if there are failures in a package - run_tests(&blackbox_solver, package, pattern, args.show_output, &args.compile_options)?; + run_tests( + &workspace_file_manager, + &blackbox_solver, + package, + pattern, + args.show_output, + &args.compile_options, + )?; } Ok(()) } fn run_tests( + file_manager: &FileManager, blackbox_solver: &S, package: &Package, fn_name: FunctionNameMatch, show_output: bool, compile_options: &CompileOptions, ) -> Result<(), CliError> { - let (mut context, crate_id) = prepare_package(package); + let (mut context, crate_id) = prepare_package(file_manager, package); check_crate_and_report_errors( &mut context, crate_id, diff --git a/tooling/nargo_cli/src/cli/verify_cmd.rs b/tooling/nargo_cli/src/cli/verify_cmd.rs index 9659286b5ab..86d5e774cbe 100644 --- a/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -7,11 +7,14 @@ use crate::{backends::Backend, errors::CliError}; use clap::Args; use nargo::constants::{PROOF_EXT, VERIFIER_INPUT_FILE}; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo::package::Package; use nargo::workspace::Workspace; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::input_parser::Format; -use noirc_driver::{CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING}; +use noirc_driver::{ + file_manager_with_stdlib, CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, +}; use noirc_frontend::graph::CrateName; /// Given a proof and a program, verify whether the proof is valid @@ -48,10 +51,18 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; + let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); + insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + let expression_width = backend.get_backend_info()?; for package in &workspace { - let program = - compile_bin_package(&workspace, package, &args.compile_options, expression_width)?; + let program = compile_bin_package( + &workspace_file_manager, + &workspace, + package, + &args.compile_options, + expression_width, + )?; verify_package(backend, &workspace, package, program, &args.verifier_name)?; }