diff --git a/.github/workflows/gates_report.yml b/.github/workflows/gates_report.yml new file mode 100644 index 00000000000..e2d6bdd56b7 --- /dev/null +++ b/.github/workflows/gates_report.yml @@ -0,0 +1,90 @@ +name: Report gates diff + +on: + push: + branches: + - master + pull_request: + +jobs: + build-nargo: + runs-on: ubuntu-latest + strategy: + matrix: + target: [x86_64-unknown-linux-gnu] + + steps: + - name: Checkout Noir repo + uses: actions/checkout@v4 + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.66.0 + + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} + + - name: Build Nargo + run: cargo build --package nargo_cli --release + + - name: Package artifacts + run: | + mkdir dist + cp ./target/release/nargo ./dist/nargo + 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-x86_64-unknown-linux-gnu.tar.gz + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: nargo + path: ./dist/* + retention-days: 3 + + + compare_gas_reports: + needs: [build-nargo] + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Download nargo binary + uses: actions/download-artifact@v3 + with: + name: nargo + path: ./nargo + + - name: Set nargo on PATH + run: | + nargo_binary="${{ github.workspace }}/nargo/nargo" + chmod +x $nargo_binary + echo "$(dirname $nargo_binary)" >> $GITHUB_PATH + export PATH="$PATH:$(dirname $nargo_binary)" + nargo -V + + - name: Generate gates report + working-directory: ./tooling/nargo_cli/tests + run: | + ./gates_report.sh + mv gates_report.json ../../../gates_report.json + + - name: Compare gates reports + id: gates_diff + uses: TomAFrench/noir-gates-diff@e7cf131b7e7f044c01615f93f0b855f65ddc02d4 + with: + report: gates_report.json + summaryQuantile: 0.9 # only display the 10% most significant circuit size diffs in the summary (defaults to 20%) + + - name: Add gates diff to sticky comment + if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' + uses: marocchino/sticky-pull-request-comment@v2 + with: + # delete the comment in case changes no longer impact circuit sizes + delete: ${{ !steps.gates_diff.outputs.markdown }} + message: ${{ steps.gates_diff.outputs.markdown }} diff --git a/.gitignore b/.gitignore index 94e8f1a8db0..169353af2b6 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,9 @@ result !tooling/nargo_cli/tests/acir_artifacts/*/target !tooling/nargo_cli/tests/acir_artifacts/*/target/witness.gz !compiler/wasm/noir-script/target + +gates_report.json + # Github Actions scratch space # This gives a location to download artifacts into the repository in CI without making git dirty. libbarretenberg-wasm32 diff --git a/Cargo.lock b/Cargo.lock index c9c60fc62ed..037db4f72ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1116,16 +1116,6 @@ dependencies = [ "itertools", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -2542,6 +2532,7 @@ name = "noir_debugger" version = "0.17.0" dependencies = [ "acvm", + "codespan-reporting", "easy-repl", "nargo", "noirc_printable_type", @@ -2633,6 +2624,7 @@ version = "0.17.0" dependencies = [ "acvm", "base64", + "build-data", "clap", "fm", "fxhash", @@ -3187,9 +3179,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -3197,14 +3189,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] diff --git a/compiler/noirc_driver/Cargo.toml b/compiler/noirc_driver/Cargo.toml index f1c21f74aab..f1c120e1687 100644 --- a/compiler/noirc_driver/Cargo.toml +++ b/compiler/noirc_driver/Cargo.toml @@ -7,6 +7,9 @@ license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[build-dependencies] +build-data = "0.1.3" + [dependencies] clap.workspace = true noirc_errors.workspace = true diff --git a/compiler/noirc_driver/build.rs b/compiler/noirc_driver/build.rs new file mode 100644 index 00000000000..7b5a645c026 --- /dev/null +++ b/compiler/noirc_driver/build.rs @@ -0,0 +1,14 @@ +const GIT_COMMIT: &&str = &"GIT_COMMIT"; + +fn main() { + // Rebuild if the tests have changed + println!("cargo:rerun-if-changed=tests"); + + // Only use build_data if the environment variable isn't set + // The environment variable is always set when working via Nix + if std::env::var(GIT_COMMIT).is_err() { + build_data::set_GIT_COMMIT(); + build_data::set_GIT_DIRTY(); + build_data::no_debug_rebuilds(); + } +} diff --git a/compiler/noirc_driver/src/contract.rs b/compiler/noirc_driver/src/contract.rs index a16da313ff6..da097d4cb86 100644 --- a/compiler/noirc_driver/src/contract.rs +++ b/compiler/noirc_driver/src/contract.rs @@ -28,6 +28,8 @@ pub enum ContractFunctionType { #[derive(Serialize, Deserialize)] pub struct CompiledContract { + pub noir_version: String, + /// The name of the contract. pub name: String, /// Each of the contract's functions are compiled into a separate `CompiledProgram` diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 44e50f94874..f8908efc596 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -28,6 +28,15 @@ pub use program::CompiledProgram; const STD_CRATE_NAME: &str = "std"; +pub const GIT_COMMIT: &str = env!("GIT_COMMIT"); +pub const GIT_DIRTY: &str = env!("GIT_DIRTY"); +pub const NOIRC_VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Version string that gets placed in artifacts that Noir builds. This is semver compatible. +/// Note: You can't directly use the value of a constant produced with env! inside a concat! macro. +pub const NOIR_ARTIFACT_VERSION_STRING: &str = + concat!(env!("CARGO_PKG_VERSION"), "+", env!("GIT_COMMIT")); + #[derive(Args, Clone, Debug, Default, Serialize, Deserialize)] pub struct CompileOptions { /// Emit debug information for the intermediate SSA IR @@ -305,6 +314,7 @@ fn compile_contract_inner( .collect(), functions, file_map, + noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), }) } else { Err(errors) @@ -342,5 +352,12 @@ pub fn compile_no_check( let file_map = filter_relevant_files(&[debug.clone()], &context.file_manager); - Ok(CompiledProgram { hash, circuit, debug, abi, file_map }) + Ok(CompiledProgram { + hash, + circuit, + debug, + abi, + file_map, + noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), + }) } diff --git a/compiler/noirc_driver/src/program.rs b/compiler/noirc_driver/src/program.rs index 8a13092aeb6..fe991567180 100644 --- a/compiler/noirc_driver/src/program.rs +++ b/compiler/noirc_driver/src/program.rs @@ -12,6 +12,7 @@ use super::debug::DebugFile; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct CompiledProgram { + pub noir_version: String, /// Hash of the [`Program`][noirc_frontend::monomorphization::ast::Program] from which this [`CompiledProgram`] /// was compiled. /// diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index d846ede566f..9c820220e07 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -427,20 +427,10 @@ impl AcirContext { let diff_expr = &lhs_expr - &rhs_expr; // Check to see if equality can be determined at compile-time. - if diff_expr.is_const() { - if diff_expr.is_zero() { - // Constraint is always true - assertion is unnecessary. - self.mark_variables_equivalent(lhs, rhs)?; - return Ok(()); - } else { - // Constraint is always false - this program is unprovable. - return Err(RuntimeError::FailedConstraint { - lhs: Box::new(lhs_expr), - rhs: Box::new(rhs_expr), - call_stack: self.get_call_stack(), - assert_message, - }); - }; + if diff_expr.is_zero() { + // Constraint is always true - assertion is unnecessary. + self.mark_variables_equivalent(lhs, rhs)?; + return Ok(()); } self.acir_ir.assert_is_zero(diff_expr); 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 a458814ce9e..aa2bedb37b7 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -1173,6 +1173,11 @@ fn resolve_function_set( resolver.set_self_type(self_type.clone()); resolver.set_trait_id(unresolved_functions.trait_id); + // Without this, impl methods can accidentally be placed in contracts. See #3254 + if self_type.is_some() { + resolver.set_in_contract(false); + } + let (hir_func, func_meta, errs) = resolver.resolve_function(func, func_id); interner.push_fn_meta(func_meta, func_id); interner.update_fn(func_id, hir_func); diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index a4a85d85929..d527433630f 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -87,6 +87,14 @@ pub struct Resolver<'a> { /// Set to the current type if we're resolving an impl self_type: Option, + /// True if the current module is a contract. + /// This is usually determined by self.path_resolver.module_id(), but it can + /// be overriden for impls. Impls are an odd case since the methods within resolve + /// as if they're in the parent module, but should be placed in a child module. + /// Since they should be within a child module, in_contract is manually set to false + /// for these so we can still resolve them in the parent module without them being in a contract. + in_contract: bool, + /// Contains a mapping of the current struct or functions's generics to /// unique type variables if we're resolving a struct. Empty otherwise. /// This is a Vec rather than a map to preserve the order a functions generics @@ -119,6 +127,9 @@ impl<'a> Resolver<'a> { def_maps: &'a BTreeMap, file: FileId, ) -> Resolver<'a> { + let module_id = path_resolver.module_id(); + let in_contract = module_id.module(def_maps).is_contract; + Self { path_resolver, def_maps, @@ -131,6 +142,7 @@ impl<'a> Resolver<'a> { errors: Vec::new(), lambda_stack: Vec::new(), file, + in_contract, } } @@ -805,9 +817,16 @@ impl<'a> Resolver<'a> { } } + /// Override whether this name resolver is within a contract or not. + /// This will affect which types are allowed as parameters to methods as well + /// as which modifiers are allowed on a function. + pub(crate) fn set_in_contract(&mut self, in_contract: bool) { + self.in_contract = in_contract; + } + /// True if the 'pub' keyword is allowed on parameters in this function fn pub_allowed(&self, func: &NoirFunction) -> bool { - if self.in_contract() { + if self.in_contract { !func.def.is_unconstrained } else { func.name() == MAIN_FUNCTION @@ -815,7 +834,7 @@ impl<'a> Resolver<'a> { } fn is_entry_point_function(&self, func: &NoirFunction) -> bool { - if self.in_contract() { + if self.in_contract { func.attributes().is_contract_entry_point() } else { func.name() == MAIN_FUNCTION @@ -824,7 +843,7 @@ impl<'a> Resolver<'a> { /// True if the `distinct` keyword is allowed on a function's return type fn distinct_allowed(&self, func: &NoirFunction) -> bool { - if self.in_contract() { + if self.in_contract { // "open" and "unconstrained" functions are compiled to brillig and thus duplication of // witness indices in their abis is not a concern. !func.def.is_unconstrained && !func.def.is_open @@ -836,7 +855,7 @@ impl<'a> Resolver<'a> { fn handle_function_type(&mut self, function: &FuncId) { let function_type = self.interner.function_modifiers(function).contract_function_type; - if !self.in_contract() && function_type == Some(ContractFunctionType::Open) { + if !self.in_contract && function_type == Some(ContractFunctionType::Open) { let span = self.interner.function_ident(function).span(); self.errors.push(ResolverError::ContractFunctionTypeInNormalFunction { span }); self.interner.function_modifiers_mut(function).contract_function_type = None; @@ -844,7 +863,7 @@ impl<'a> Resolver<'a> { } fn handle_is_function_internal(&mut self, function: &FuncId) { - if !self.in_contract() { + if !self.in_contract { if self.interner.function_modifiers(function).is_internal == Some(true) { let span = self.interner.function_ident(function).span(); self.push_err(ResolverError::ContractFunctionInternalInNormalFunction { span }); @@ -1605,11 +1624,6 @@ impl<'a> Resolver<'a> { } } - fn in_contract(&self) -> bool { - let module_id = self.path_resolver.module_id(); - module_id.module(self.def_maps).is_contract - } - fn resolve_fmt_str_literal(&mut self, str: String, call_expr_span: Span) -> HirLiteral { let re = Regex::new(r"\{([a-zA-Z0-9_]+)\}") .expect("ICE: an invalid regex pattern was used for checking format strings"); diff --git a/compiler/wasm/build.rs b/compiler/wasm/build.rs index 3b96be74ef3..dc46037a1d9 100644 --- a/compiler/wasm/build.rs +++ b/compiler/wasm/build.rs @@ -1,14 +1,4 @@ -const GIT_COMMIT: &&str = &"GIT_COMMIT"; - fn main() { - // Only use build_data if the environment variable isn't set - // The environment variable is always set when working via Nix - if std::env::var(GIT_COMMIT).is_err() { - build_data::set_GIT_COMMIT(); - build_data::set_GIT_DIRTY(); - build_data::no_debug_rebuilds(); - } - build_data::set_SOURCE_TIMESTAMP(); build_data::no_debug_rebuilds(); } diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index 0f7baff4819..66f08dbabf5 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -7,7 +7,7 @@ use nargo::artifacts::{ }; use noirc_driver::{ add_dep, compile_contract, compile_main, prepare_crate, prepare_dependency, CompileOptions, - CompiledContract, CompiledProgram, + CompiledContract, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, }; use noirc_frontend::{graph::CrateGraph, hir::Context}; use std::path::Path; @@ -118,6 +118,7 @@ fn preprocess_program(program: CompiledProgram) -> PreprocessedProgram { hash: program.hash, backend: String::from(BACKEND_IDENTIFIER), abi: program.abi, + noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), bytecode: program.circuit, } } @@ -136,6 +137,7 @@ fn preprocess_contract(contract: CompiledContract) -> PreprocessedContract { .collect(); PreprocessedContract { + noir_version: String::from(NOIR_ARTIFACT_VERSION_STRING), name: contract.name, backend: String::from(BACKEND_IDENTIFIER), functions: preprocessed_functions, diff --git a/compiler/wasm/src/lib.rs b/compiler/wasm/src/lib.rs index 3a8e00bc6dd..9f2f558f85c 100644 --- a/compiler/wasm/src/lib.rs +++ b/compiler/wasm/src/lib.rs @@ -7,6 +7,7 @@ use getrandom as _; use gloo_utils::format::JsValueSerdeExt; use log::Level; +use noirc_driver::{GIT_COMMIT, GIT_DIRTY, NOIRC_VERSION}; use serde::{Deserialize, Serialize}; use std::str::FromStr; use wasm_bindgen::prelude::*; @@ -37,11 +38,8 @@ pub fn init_log_level(level: String) { }); } -const BUILD_INFO: BuildInfo = BuildInfo { - git_hash: env!("GIT_COMMIT"), - version: env!("CARGO_PKG_VERSION"), - dirty: env!("GIT_DIRTY"), -}; +const BUILD_INFO: BuildInfo = + BuildInfo { git_hash: GIT_COMMIT, version: NOIRC_VERSION, dirty: GIT_DIRTY }; #[wasm_bindgen] pub fn build_info() -> JsValue { diff --git a/cspell.json b/cspell.json index ac7953e0653..4df858ffcfa 100644 --- a/cspell.json +++ b/cspell.json @@ -88,6 +88,7 @@ "prettytable", "printstd", "pseudocode", + "quantile", "rustc", "rustup", "schnorr", diff --git a/docs/docs/language_concepts/01_functions.md b/docs/docs/language_concepts/01_functions.md index 2168c9203b6..22ee43681e5 100644 --- a/docs/docs/language_concepts/01_functions.md +++ b/docs/docs/language_concepts/01_functions.md @@ -148,19 +148,21 @@ See [Lambdas](./08_lambdas.md) for more details. Attributes are metadata that can be applied to a function, using the following syntax: `#[attribute(value)]`. Supported attributes include: + - **builtin**: the function is implemented by the compiler, for efficiency purposes. -- **deprecated**: mark the function as *deprecated*. Calling the function will generate a warning: `warning: use of deprecated function` +- **deprecated**: mark the function as _deprecated_. Calling the function will generate a warning: `warning: use of deprecated function` - **field**: Used to enable conditional compilation of code depending on the field size. See below for more details -- **oracle**: mark the function as *oracle*; meaning it is an external unconstrained function, implemented in noir_js. See [Unconstrained](./05_unconstrained.md) and [Noir js](../noir_js/noir_js.md) for more details. +- **oracle**: mark the function as _oracle_; meaning it is an external unconstrained function, implemented in noir_js. See [Unconstrained](./05_unconstrained.md) and [NoirJS](../noir_js/noir_js.md) for more details. - **test**: mark the function as unit tests. See [Tests](../nargo/02_testing.md) for more details ### Field Attribute + The field attribute defines which field the function is compatible for. The function is conditionally compiled, under the condition that the field attribute matches the Noir native field. The field can be defined implicitly, by using the name of the elliptic curve usually associated to it - for instance bn254, bls12_381 - or explicitly by using the field (prime) order, in decimal or hexadecimal form. As a result, it is possible to define multiple versions of a function with each version specialized for a different field attribute. This can be useful when a function requires different parameters depending on the underlying elliptic curve. - Example: we define the function `foo()` three times below. Once for the default Noir bn254 curve, once for the field $\mathbb F_{23}$, which will normally never be used by Noir, and once again for the bls12_381 curve. + ```rust #[field(bn254)] fn foo() -> u32 { @@ -184,4 +186,4 @@ fn foo() -> u32 { } ``` -If the field name is not known to Noir, it will discard the function. Field names are case insensitive. \ No newline at end of file +If the field name is not known to Noir, it will discard the function. Field names are case insensitive. diff --git a/docs/docs/nargo/01_commands.md b/docs/docs/nargo/01_commands.md index fbbe2b27666..65e2bdb44e3 100644 --- a/docs/docs/nargo/01_commands.md +++ b/docs/docs/nargo/01_commands.md @@ -20,12 +20,12 @@ keywords: ## General options -| Option | Description | -|---------------------|------------------------------------------------------| -| `--show-ssa` | Emit debug information for the intermediate SSA IR | -| `--deny-warnings` | Quit execution when warnings are emitted | -| `--silence-warnings`| Suppress warnings | -| `-h, --help` | Print help | +| Option | Description | +| -------------------- | -------------------------------------------------- | +| `--show-ssa` | Emit debug information for the intermediate SSA IR | +| `--deny-warnings` | Quit execution when warnings are emitted | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo help [subcommand]` @@ -33,9 +33,9 @@ Prints the list of available commands or specific information of a subcommand. _Arguments_ -| Argument | Description | -|---------------|--------------------------------------------------------| -| ``| The subcommand whose help message to display | +| Argument | Description | +| -------------- | -------------------------------------------- | +| `` | The subcommand whose help message to display | ## `nargo backend` @@ -43,20 +43,20 @@ Installs and selects custom backends used to generate and verify proofs. ### Commands -| Command | Description | -|------------|--------------------------------------------------| -| `current` | Prints the name of the currently active backend | -| `ls` | Prints the list of currently installed backends | -| `use` | Select the backend to use | -| `install` | Install a new backend from a URL | -| `uninstall`| Uninstalls a backend | -| `help` | Print this message or the help of the given subcommand(s) | +| Command | Description | +| ----------- | --------------------------------------------------------- | +| `current` | Prints the name of the currently active backend | +| `ls` | Prints the list of currently installed backends | +| `use` | Select the backend to use | +| `install` | Install a new backend from a URL | +| `uninstall` | Uninstalls a backend | +| `help` | Print this message or the help of the given subcommand(s) | ### Options -| Option | Description | -|---------------|--------------| -| `-h, --help` | Print help | +| Option | Description | +| ------------ | ----------- | +| `-h, --help` | Print help | ## `nargo check` @@ -65,14 +65,14 @@ values of the Noir program respectively. ### Options -| Option | Description | -|----------------------|---------------------------------------------------| -| `--package `| The name of the package to check | -| `--workspace` | Check all packages in the workspace | -| `--print-acir` | Display the ACIR for compiled circuit | -| `--deny-warnings` | Treat all warnings as errors | -| `--silence-warnings` | Suppress warnings | -| `-h, --help` | Print help | +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to check | +| `--workspace` | Check all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ### `nargo codegen-verifier` @@ -80,14 +80,14 @@ Generate a Solidity verifier smart contract for the program. ### Options -| Option | Description | -|----------------------|---------------------------------------------------| -| `--package `| The name of the package to codegen | -| `--workspace` | Codegen all packages in the workspace | -| `--print-acir` | Display the ACIR for compiled circuit | -| `--deny-warnings` | Treat all warnings as errors | -| `--silence-warnings` | Suppress warnings | -| `-h, --help` | Print help | +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to codegen | +| `--workspace` | Codegen all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo compile` @@ -98,15 +98,15 @@ You can also use "build" as an alias for compile (e.g. `nargo build`). ### Options -| Option | Description | -|----------------------|----------------------------------------------------| -| `--include-keys` | Include Proving and Verification keys in the build artifacts | -| `--package `| The name of the package to compile | -| `--workspace` | Compile all packages in the workspace | -| `--print-acir` | Display the ACIR for compiled circuit | -| `--deny-warnings` | Treat all warnings as errors | -| `--silence-warnings` | Suppress warnings | -| `-h, --help` | Print help | +| Option | Description | +| --------------------- | ------------------------------------------------------------ | +| `--include-keys` | Include Proving and Verification keys in the build artifacts | +| `--package ` | The name of the package to compile | +| `--workspace` | Compile all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo new ` @@ -114,19 +114,19 @@ Creates a new Noir project in a new folder. **Arguments** -| Argument | Description | -|-----------|------------------------------------| -| `` | The path to save the new project | +| Argument | Description | +| -------- | -------------------------------- | +| `` | The path to save the new project | ### Options -| Option | Description | -|-------------------|-------------------------------------------------| -| `--name ` | Name of the package [default: package directory name] | -| `--lib` | Use a library template | -| `--bin` | Use a binary template [default] | -| `--contract` | Use a contract template | -| `-h, --help` | Print help | +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: package directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | ## `nargo init` @@ -134,13 +134,13 @@ Creates a new Noir project in the current directory. ### Options -| Option | Description | -|-------------------|-------------------------------------------------| -| `--name ` | Name of the package [default: current directory name] | -| `--lib` | Use a library template | -| `--bin` | Use a binary template [default] | -| `--contract` | Use a contract template | -| `-h, --help` | Print help | +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: current directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | ## `nargo execute [WITNESS_NAME]` @@ -148,21 +148,21 @@ Runs the Noir program and prints its return value. **Arguments** -| Argument | Description | -|-----------------|------------------------------------------------| -| `[WITNESS_NAME]`| Write the execution witness to named file | +| Argument | Description | +| ---------------- | ----------------------------------------- | +| `[WITNESS_NAME]` | Write the execution witness to named file | ### Options -| Option | Description | -|-------------------------------|------------------------------------------------------------------| +| Option | Description | +| --------------------------------- | ------------------------------------------------------------------------------------ | | `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | -| `--package ` | The name of the package to execute | -| `--workspace` | Execute all packages in the workspace | -| `--print-acir` | Display the ACIR for compiled circuit | -| `--deny-warnings` | Treat all warnings as errors | -| `--silence-warnings` | Suppress warnings | -| `-h, --help` | Print help | +| `--package ` | The name of the package to execute | +| `--workspace` | Execute all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | _Usage_ @@ -178,17 +178,17 @@ Creates a proof for the program. ### Options -| Option | Description | -|-------------------------------|------------------------------------------------------------------| -| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | | `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | -| `--verify` | Verify proof after proving | -| `--package ` | The name of the package to prove | -| `--workspace` | Prove all packages in the workspace | -| `--print-acir` | Display the ACIR for compiled circuit | -| `--deny-warnings` | Treat all warnings as errors | -| `--silence-warnings` | Suppress warnings | -| `-h, --help` | Print help | +| `--verify` | Verify proof after proving | +| `--package ` | The name of the package to prove | +| `--workspace` | Prove all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo verify` @@ -196,15 +196,15 @@ Given a proof and a program, verify whether the proof is valid. ### Options -| Option | Description | -|-------------------------------|------------------------------------------------------------------| +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | | `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | -| `--package ` | The name of the package to verify | -| `--workspace` | Verify all packages in the workspace | -| `--print-acir` | Display the ACIR for compiled circuit | -| `--deny-warnings` | Treat all warnings as errors | -| `--silence-warnings` | Suppress warnings | -| `-h, --help` | Print help | +| `--package ` | The name of the package to verify | +| `--workspace` | Verify all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo test [TEST_NAME]` @@ -217,16 +217,16 @@ See an example on the [testing page](./testing). ### Options -| Option | Description | -|----------------------|---------------------------------------------------| -| `--show-output` | Display output of `println` statements | -| `--exact` | Only run tests that match exactly | -| `--package `| The name of the package to test | -| `--workspace` | Test all packages in the workspace | -| `--print-acir` | Display the ACIR for compiled circuit | -| `--deny-warnings` | Treat all warnings as errors | -| `--silence-warnings` | Suppress warnings | -| `-h, --help` | Print help | +| Option | Description | +| --------------------- | -------------------------------------- | +| `--show-output` | Display output of `println` statements | +| `--exact` | Only run tests that match exactly | +| `--package ` | The name of the package to test | +| `--workspace` | Test all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | ## `nargo info` @@ -244,3 +244,7 @@ above information about each function of the contract. Start a long-running Language Server process that communicates over stdin/stdout. Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). + +## `nargo fmt` + +Automatically formats your Noir source code based on the default formatting settings. diff --git a/docs/docs/nargo/04_language_server.md b/docs/docs/nargo/04_language_server.md index 543af9ec5ff..144cd249c4b 100644 --- a/docs/docs/nargo/04_language_server.md +++ b/docs/docs/nargo/04_language_server.md @@ -25,7 +25,7 @@ Currently, Noir provides a Language Client for Visual Studio Code via the [vscod > > If LSP features seem to be missing / malfunctioning, make sure you are opening your Noir project directly (instead of as a sub-folder) in your VSCode instance. -When you language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, execution, and tests: +When your language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, measuring circuit size, execution, and tests: ![Compile and Execute](./../../static/img/codelens_compile_execute.png) ![Run test](../../static/img/codelens_run_test.png) diff --git a/docs/docs/noir_js/getting_started/01_tiny_noir_app.md b/docs/docs/noir_js/getting_started/01_tiny_noir_app.md index 9878554dd60..c450427e8f7 100644 --- a/docs/docs/noir_js/getting_started/01_tiny_noir_app.md +++ b/docs/docs/noir_js/getting_started/01_tiny_noir_app.md @@ -1,10 +1,10 @@ --- -title: Full Stack Noir App +title: End-to-end description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs] --- -Noir JS works both on the browser and on the server, and works for both ESM and CJS module systems. In this page, we will learn how can we write a simple test and a simple web app to verify the standard Noir example. +NoirJS works both on the browser and on the server, and works for both ESM and CJS module systems. In this page, we will learn how can we write a simple test and a simple web app to verify the standard Noir example. ## Before we start diff --git a/docs/docs/noir_js/noir_js.md b/docs/docs/noir_js/noir_js.md index baaf409b522..23ea550e156 100644 --- a/docs/docs/noir_js/noir_js.md +++ b/docs/docs/noir_js/noir_js.md @@ -1,22 +1,36 @@ --- -title: Noir JS -description: Learn how to use noir js to use Noir in a Typescript or Javascript environment +title: NoirJS +description: Interact with Noir in Typescript or Javascript keywords: [Noir project, javascript, typescript, node.js, browser, react] --- -Noir JS are a set of typescript libraries that make it easy to use Noir on your dapp, webapp, node.js server, website, etc. +NoirJS is a TypeScript library that make it easy to use Noir on your dapp, webapp, Node.js server, website, etc. -It is composed of two major elements: +A typical workflow would be composed of two major elements: -- Noir -- Backend proving system +- NoirJS +- Proving backend of choice's JavaScript package -Your only concern should be to write Noir. Noir.js will work out-of-the box and abstract all the components, such as the ACVM and others. +To install NoirJS, install Node.js if you have not already and run this in your JavaScript project: -## Barretenberg +```bash +npm i @noir-lang/noir_js +``` -Since Noir is backend agnostic, you can instantiate `noir_js` without any backend (i.e. to execute a function). But for proving, you should instantiate it with any of the supported backends through their own `js` interface. +## Proving backend -Aztec Labs maintains the `barretenberg` backend. You can use it to instantiate your `Noir` class. +Since Noir is backend agnostic, you can instantiate NoirJS without any backend (i.e. to execute a function). But for proving, you would have to instantiate NoirJS with any of the supported backends through their own `js` interface. + +### Barretenberg + +Aztec Labs maintains the `barretenberg` proving backend, which you can instantiate and make use of alongside NoirJS. It is also the default proving backend installed and used with Nargo, the Noir CLI tool. + +To install its JavaScript library, run this in your project: + +```bash +npm i @noir-lang/backend_barretenberg +``` + +For more details on how to instantiate and use the libraries, refer to the [Full Noir App Guide](./getting_started/01_tiny_noir_app.md) and [Reference](./reference/01_noirjs.md) sections. diff --git a/docs/docs/noir_js/reference/02_noirjs.md b/docs/docs/noir_js/reference/01_noirjs.md similarity index 100% rename from docs/docs/noir_js/reference/02_noirjs.md rename to docs/docs/noir_js/reference/01_noirjs.md diff --git a/docs/docs/noir_js/reference/01_bb_backend.md b/docs/docs/noir_js/reference/02_bb_backend.md similarity index 99% rename from docs/docs/noir_js/reference/01_bb_backend.md rename to docs/docs/noir_js/reference/02_bb_backend.md index 446bf9820ea..21c2ff32b57 100644 --- a/docs/docs/noir_js/reference/01_bb_backend.md +++ b/docs/docs/noir_js/reference/02_bb_backend.md @@ -41,7 +41,7 @@ constructor(acirCircuit, (numberOfThreads = 1)); | Parameter | Type | Description | | ----------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `acirCircuit` | Object | A circuit represented in a `json` format, containing the ABI and bytecode Tipically obtained by running [`nargo compile`](../../nargo/01_commands.md). This is the same circuit expected to be passed to [the Noir class](02_noirjs.md) | +| `acirCircuit` | Object | A circuit represented in a `json` format, containing the ABI and bytecode Tipically obtained by running [`nargo compile`](../../nargo/01_commands.md). This is the same circuit expected to be passed to [the Noir class](01_noirjs.md) | | `numberOfThreads` | Number (optional) | The number of threads to be used by the backend. Defaults to 1. | ### Usage diff --git a/docs/sidebars.js b/docs/sidebars.js index 205ecb76038..8fddb677a58 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -98,7 +98,7 @@ const sidebars = { }, { type: 'category', - label: 'Noir JS', + label: 'NoirJS', link: { type: 'doc', id: 'noir_js/noir_js', @@ -106,21 +106,21 @@ const sidebars = { items: [ { type: 'category', - label: 'Reference', + label: 'Guides', items: [ { type: 'autogenerated', - dirName: 'noir_js/reference', + dirName: 'noir_js/getting_started', }, ], }, { type: 'category', - label: 'Guides', + label: 'Reference', items: [ { type: 'autogenerated', - dirName: 'noir_js/getting_started', + dirName: 'noir_js/reference', }, ], }, diff --git a/docs/static/img/codelens_compile_execute.png b/docs/static/img/codelens_compile_execute.png index 347490f529f..040e3af2704 100644 Binary files a/docs/static/img/codelens_compile_execute.png and b/docs/static/img/codelens_compile_execute.png differ diff --git a/docs/static/img/codelens_run_test.png b/docs/static/img/codelens_run_test.png index 3ff94df0903..568869fb839 100644 Binary files a/docs/static/img/codelens_run_test.png and b/docs/static/img/codelens_run_test.png differ diff --git a/noir_stdlib/src/sha256.nr b/noir_stdlib/src/sha256.nr index f6c22aa1d5f..d2afd21db8a 100644 --- a/noir_stdlib/src/sha256.nr +++ b/noir_stdlib/src/sha256.nr @@ -5,7 +5,9 @@ // Auxiliary mappings; names as in FIPS PUB 180-4 fn rotr32(a: u32, b: u32) -> u32 // 32-bit right rotation { - (a >> b) | (a << (32 as u32 - b)) + // None of the bits overlap between `(a >> b)` and `(a << (32 - b))` + // Addition is then equivalent to OR, with fewer constraints. + (a >> b) + (a << (32 - b)) } fn ch(x: u32, y: u32, z: u32) -> u32 diff --git a/noir_stdlib/src/sha512.nr b/noir_stdlib/src/sha512.nr index e5cac7b1554..c565b16c098 100644 --- a/noir_stdlib/src/sha512.nr +++ b/noir_stdlib/src/sha512.nr @@ -5,7 +5,9 @@ // Auxiliary mappings; names as in FIPS PUB 180-4 fn rotr64(a: u64, b: u64) -> u64 // 64-bit right rotation { - (a >> b) | (a << (64 - b)) + // None of the bits overlap between `(a >> b)` and `(a << (64 - b))` + // Addition is then equivalent to OR, with fewer constraints. + (a >> b) + (a << (64 - b)) } fn sha_ch(x: u64, y: u64, z: u64) -> u64 diff --git a/release-tests/test/version.test.js b/release-tests/test/version.test.js index 07051d1edce..7a70639d83e 100644 --- a/release-tests/test/version.test.js +++ b/release-tests/test/version.test.js @@ -21,9 +21,12 @@ test("promise resolved", async () => { test("prints version", async () => { const processOutput = (await $`${NARGO_BIN} --version`).toString(); - assert.match(processOutput, /nargo\s\d{1,2}.\d{1,2}/); + + // Regex to match the "nargo version" part of the output + assert.match(processOutput, /nargo version = \d{1,2}\.\d{1,2}\.\d{1,2}/); }); + test("reports a clean commit", async () => { const processOutput = (await $`${NARGO_BIN} --version`).toString(); assert.not.match(processOutput, /is dirty: true/) diff --git a/tooling/debugger/Cargo.toml b/tooling/debugger/Cargo.toml index e01abd9ac61..1f9a54b4fe8 100644 --- a/tooling/debugger/Cargo.toml +++ b/tooling/debugger/Cargo.toml @@ -13,5 +13,6 @@ acvm.workspace = true nargo.workspace = true noirc_printable_type.workspace = true thiserror.workspace = true +codespan-reporting.workspace = true easy-repl = "0.2.1" -owo-colors = "3" \ No newline at end of file +owo-colors = "3" diff --git a/tooling/debugger/src/lib.rs b/tooling/debugger/src/lib.rs index f8e9db19234..3da9c5c7989 100644 --- a/tooling/debugger/src/lib.rs +++ b/tooling/debugger/src/lib.rs @@ -4,16 +4,21 @@ use acvm::BlackBoxFunctionSolver; use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; use nargo::artifacts::debug::DebugArtifact; -use nargo::errors::ExecutionError; +use nargo::errors::{ExecutionError, Location}; use nargo::NargoError; use nargo::ops::ForeignCallExecutor; use easy_repl::{command, CommandStatus, Critical, Repl}; -use std::cell::{Cell, RefCell}; +use std::{ + cell::{Cell, RefCell}, + ops::Range, +}; use owo_colors::OwoColorize; +use codespan_reporting::files::Files; + enum SolveResult { Done, Ok, @@ -74,25 +79,72 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { println!("Finished execution"); } else { println!("Stopped at opcode {}: {}", ip, opcodes[ip]); - Self::show_source_code_location(&OpcodeLocation::Acir(ip), &self.debug_artifact); + self.show_source_code_location(&OpcodeLocation::Acir(ip), &self.debug_artifact); } } - fn show_source_code_location(location: &OpcodeLocation, debug_artifact: &DebugArtifact) { + fn print_location_path(&self, loc: Location) { + let line_number = self.debug_artifact.location_line_number(loc).unwrap(); + let column_number = self.debug_artifact.location_column_number(loc).unwrap(); + + println!( + "At {}:{line_number}:{column_number}", + self.debug_artifact.name(loc.file).unwrap() + ); + } + + fn show_source_code_location(&self, location: &OpcodeLocation, debug_artifact: &DebugArtifact) { let locations = debug_artifact.debug_symbols[0].opcode_location(location); - if let Some(locations) = locations { - for loc in locations { - let file = &debug_artifact.file_map[&loc.file]; - let source = &file.source.as_str(); - let start = loc.span.start() as usize; - let end = loc.span.end() as usize; - println!("At {}:{start}-{end}", file.path.as_path().display()); - println!( - "\n{}{}{}\n", - &source[0..start].to_string().dimmed(), - &source[start..end], - &source[end..].to_string().dimmed(), - ); + let Some(locations) = locations else { return }; + for loc in locations { + self.print_location_path(loc); + + let loc_line_index = debug_artifact.location_line_index(loc).unwrap(); + + // How many lines before or after the location's line we + // print + let context_lines = 5; + + let first_line_to_print = + if loc_line_index < context_lines { 0 } else { loc_line_index - context_lines }; + + let last_line_index = debug_artifact.last_line_index(loc).unwrap(); + let last_line_to_print = std::cmp::min(loc_line_index + context_lines, last_line_index); + + let source = debug_artifact.location_source_code(loc).unwrap(); + for (current_line_index, line) in source.lines().enumerate() { + let current_line_number = current_line_index + 1; + + if current_line_index < first_line_to_print { + // Ignore lines before range starts + continue; + } else if current_line_index == first_line_to_print && current_line_index > 0 { + // Denote that there's more lines before but we're not showing them + print_line_of_ellipsis(current_line_index); + } + + if current_line_index > last_line_to_print { + // Denote that there's more lines after but we're not showing them, + // and stop printing + print_line_of_ellipsis(current_line_number); + break; + } + + if current_line_index == loc_line_index { + // Highlight current location + let Range { start: loc_start, end: loc_end } = + debug_artifact.location_in_line(loc).unwrap(); + println!( + "{:>3} {:2} {}{}{}", + current_line_number, + "->", + &line[0..loc_start].to_string().dimmed(), + &line[loc_start..loc_end], + &line[loc_end..].to_string().dimmed() + ); + } else { + print_dimmed_line(current_line_number, line); + } } } } @@ -112,6 +164,14 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { } } +fn print_line_of_ellipsis(line_number: usize) { + println!("{}", format!("{:>3} {}", line_number, "...").dimmed()); +} + +fn print_dimmed_line(line_number: usize, line: &str) { + println!("{}", format!("{:>3} {:2} {}", line_number, "", line).dimmed()); +} + fn map_command_status(result: SolveResult) -> CommandStatus { match result { SolveResult::Ok => CommandStatus::Done, diff --git a/tooling/nargo/src/artifacts/contract.rs b/tooling/nargo/src/artifacts/contract.rs index fa161b63a5b..4f1ae0e10a0 100644 --- a/tooling/nargo/src/artifacts/contract.rs +++ b/tooling/nargo/src/artifacts/contract.rs @@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize}; /// - Proving and verification keys have been pregenerated based on this ACIR. #[derive(Serialize, Deserialize)] pub struct PreprocessedContract { + /// Version of noir used to compile this contract + pub noir_version: String, /// The name of the contract. pub name: String, /// The identifier of the proving backend which this contract has been compiled for. diff --git a/tooling/nargo/src/artifacts/debug.rs b/tooling/nargo/src/artifacts/debug.rs index 31ce1d7bb6a..d2e2eb9f311 100644 --- a/tooling/nargo/src/artifacts/debug.rs +++ b/tooling/nargo/src/artifacts/debug.rs @@ -1,6 +1,6 @@ use codespan_reporting::files::{Error, Files, SimpleFile}; use noirc_driver::DebugFile; -use noirc_errors::debug_info::DebugInfo; +use noirc_errors::{debug_info::DebugInfo, Location}; use serde::{Deserialize, Serialize}; use std::{ collections::{BTreeMap, BTreeSet}, @@ -45,6 +45,53 @@ impl DebugArtifact { Self { debug_symbols, file_map } } + + /// Given a location, returns its file's source code + pub fn location_source_code(&self, location: Location) -> Result<&str, Error> { + self.source(location.file) + } + + /// Given a location, returns the index of the line it starts at + pub fn location_line_index(&self, location: Location) -> Result { + let location_start = location.span.start() as usize; + self.line_index(location.file, location_start) + } + + /// Given a location, returns the line number it starts at + pub fn location_line_number(&self, location: Location) -> Result { + let location_start = location.span.start() as usize; + let line_index = self.line_index(location.file, location_start)?; + self.line_number(location.file, line_index) + } + + /// Given a location, returns the column number it starts at + pub fn location_column_number(&self, location: Location) -> Result { + let location_start = location.span.start() as usize; + let line_index = self.line_index(location.file, location_start)?; + self.column_number(location.file, line_index, location_start) + } + + /// Given a location, returns a Span relative to its line's + /// position in the file. This is useful when processing a file's + /// contents on a per-line-basis. + pub fn location_in_line(&self, location: Location) -> Result, Error> { + let location_start = location.span.start() as usize; + let location_end = location.span.end() as usize; + let line_index = self.line_index(location.file, location_start)?; + let line_span = self.line_range(location.file, line_index)?; + + let start_in_line = location_start - line_span.start; + let end_in_line = location_end - line_span.start; + + Ok(Range { start: start_in_line, end: end_in_line }) + } + + /// Given a location, returns the last line index + /// of its file + pub fn last_line_index(&self, location: Location) -> Result { + let source = self.source(location.file)?; + self.line_index(location.file, source.len()) + } } impl<'a> Files<'a> for DebugArtifact { diff --git a/tooling/nargo/src/artifacts/program.rs b/tooling/nargo/src/artifacts/program.rs index 190b4c76897..5988f3f59cb 100644 --- a/tooling/nargo/src/artifacts/program.rs +++ b/tooling/nargo/src/artifacts/program.rs @@ -9,6 +9,8 @@ use serde::{Deserialize, Serialize}; /// - Proving and verification keys have been pregenerated based on this ACIR. #[derive(Serialize, Deserialize, Debug)] pub struct PreprocessedProgram { + pub noir_version: String, + /// Hash of the [`Program`][noirc_frontend::monomorphization::ast::Program] from which this [`PreprocessedProgram`] /// was compiled. /// diff --git a/tooling/nargo/src/errors.rs b/tooling/nargo/src/errors.rs index ea6e7fa8108..0c920716f2a 100644 --- a/tooling/nargo/src/errors.rs +++ b/tooling/nargo/src/errors.rs @@ -2,7 +2,10 @@ use acvm::{ acir::circuit::OpcodeLocation, pwg::{ErrorLocation, OpcodeResolutionError}, }; -use noirc_errors::{debug_info::DebugInfo, CustomDiagnostic, FileDiagnostic, Location}; +use noirc_errors::{debug_info::DebugInfo, CustomDiagnostic, FileDiagnostic}; + +pub use noirc_errors::Location; + use noirc_printable_type::ForeignCallError; use thiserror::Error; diff --git a/tooling/nargo_cli/Cargo.toml b/tooling/nargo_cli/Cargo.toml index cb824b41428..a1440dc2ecb 100644 --- a/tooling/nargo_cli/Cargo.toml +++ b/tooling/nargo_cli/Cargo.toml @@ -37,7 +37,7 @@ toml.workspace = true serde.workspace = true serde_json.workspace = true prettytable-rs = "0.10" -rayon = "1.7.0" +rayon = "1.8.0" thiserror.workspace = true tower.workspace = true async-lsp = { version = "0.0.5", default-features = false, features = [ diff --git a/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs index 35538ef1a83..856970544b8 100644 --- a/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -76,7 +76,6 @@ fn smart_contract_for_package( workspace, package, compile_options, - false, np_language, &is_opcode_supported, )?; diff --git a/tooling/nargo_cli/src/cli/compile_cmd.rs b/tooling/nargo_cli/src/cli/compile_cmd.rs index a332d63e062..56f91843914 100644 --- a/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::path::Path; use acvm::acir::circuit::Opcode; @@ -14,8 +13,8 @@ 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::NOIR_ARTIFACT_VERSION_STRING; use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram}; -use noirc_errors::debug_info::DebugInfo; use noirc_frontend::graph::CrateName; use clap::Args; @@ -23,9 +22,9 @@ use clap::Args; use crate::backends::Backend; use crate::errors::{CliError, CompileError}; -use super::fs::program::read_program_from_file; use super::fs::program::{ - save_contract_to_file, save_debug_artifact_to_file, save_program_to_file, + read_debug_artifact_from_file, read_program_from_file, save_contract_to_file, + save_debug_artifact_to_file, save_program_to_file, }; use super::NargoConfig; use rayon::prelude::*; @@ -40,10 +39,6 @@ pub(crate) struct CompileCommand { #[arg(long)] include_keys: bool, - /// Output debug files - #[arg(long, hide = true)] - output_debug: bool, - /// The name of the package to compile #[clap(long, conflicts_with = "workspace")] package: Option, @@ -82,12 +77,11 @@ pub(crate) fn run( np_language, &opcode_support, &args.compile_options, - args.output_debug, )?; // Save build artifacts to disk. for (package, contract) in contract_packages.into_iter().zip(compiled_contracts) { - save_contract(contract, &package, &circuit_dir, args.output_debug); + save_contract(contract, &package, &circuit_dir); } Ok(()) @@ -100,7 +94,6 @@ pub(super) fn compile_workspace( np_language: Language, opcode_support: &BackendOpcodeSupport, compile_options: &CompileOptions, - output_debug: bool, ) -> Result<(Vec, Vec), CliError> { let is_opcode_supported = |opcode: &_| opcode_support.is_opcode_supported(opcode); @@ -108,14 +101,7 @@ pub(super) fn compile_workspace( let program_results: Vec<(FileManager, CompilationResult)> = binary_packages .par_iter() .map(|package| { - compile_program( - workspace, - package, - compile_options, - output_debug, - np_language, - &is_opcode_supported, - ) + compile_program(workspace, package, compile_options, np_language, &is_opcode_supported) }) .collect(); let contract_results: Vec<(FileManager, CompilationResult)> = @@ -157,7 +143,6 @@ pub(crate) fn compile_bin_package( workspace: &Workspace, package: &Package, compile_options: &CompileOptions, - output_debug: bool, np_language: Language, is_opcode_supported: &impl Fn(&Opcode) -> bool, ) -> Result { @@ -165,14 +150,8 @@ 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, - output_debug, - np_language, - &is_opcode_supported, - ); + let (file_manager, compilation_result) = + compile_program(workspace, package, compile_options, np_language, &is_opcode_supported); let program = report_errors( compilation_result, @@ -188,31 +167,33 @@ fn compile_program( workspace: &Workspace, package: &Package, compile_options: &CompileOptions, - output_debug: bool, np_language: Language, is_opcode_supported: &impl Fn(&Opcode) -> bool, ) -> (FileManager, CompilationResult) { let (mut context, crate_id) = prepare_package(package, Box::new(|path| std::fs::read_to_string(path))); - let cached_program = if let Ok(preprocessed_program) = - read_program_from_file(workspace.package_build_path(package)) - { - // TODO: Load debug information. + let program_artifact_path = workspace.package_build_path(package); + let mut debug_artifact_path = program_artifact_path.clone(); + debug_artifact_path.set_file_name(format!("debug_{}.json", package.name)); + let cached_program = if let (Ok(preprocessed_program), Ok(mut debug_artifact)) = ( + read_program_from_file(program_artifact_path), + read_debug_artifact_from_file(debug_artifact_path), + ) { Some(CompiledProgram { hash: preprocessed_program.hash, circuit: preprocessed_program.bytecode, abi: preprocessed_program.abi, - debug: DebugInfo::default(), - file_map: BTreeMap::new(), + noir_version: preprocessed_program.noir_version, + debug: debug_artifact.debug_symbols.remove(0), + file_map: debug_artifact.file_map, }) } else { None }; - // If we want to output the debug information then we need to perform a full recompilation of the ACIR. - let force_recompile = output_debug; - + let force_recompile = + cached_program.as_ref().map_or(false, |p| p.noir_version != NOIR_ARTIFACT_VERSION_STRING); let (program, warnings) = match noirc_driver::compile_main( &mut context, crate_id, @@ -231,12 +212,7 @@ fn compile_program( nargo::ops::optimize_program(program, np_language, &is_opcode_supported) .expect("Backend does not support an opcode that is in the IR"); - save_program( - optimized_program.clone(), - package, - &workspace.target_directory_path(), - output_debug, - ); + save_program(optimized_program.clone(), package, &workspace.target_directory_path()); (context.file_manager, Ok((optimized_program, warnings))) } @@ -264,35 +240,24 @@ fn compile_contract( (context.file_manager, Ok((optimized_contract, warnings))) } -fn save_program( - program: CompiledProgram, - package: &Package, - circuit_dir: &Path, - output_debug: bool, -) { +fn save_program(program: CompiledProgram, package: &Package, circuit_dir: &Path) { let preprocessed_program = PreprocessedProgram { hash: program.hash, backend: String::from(BACKEND_IDENTIFIER), abi: program.abi, + noir_version: program.noir_version, bytecode: program.circuit, }; save_program_to_file(&preprocessed_program, &package.name, circuit_dir); - if output_debug { - let debug_artifact = - DebugArtifact { debug_symbols: vec![program.debug], file_map: program.file_map }; - let circuit_name: String = (&package.name).into(); - save_debug_artifact_to_file(&debug_artifact, &circuit_name, circuit_dir); - } + let debug_artifact = + DebugArtifact { debug_symbols: vec![program.debug], file_map: program.file_map }; + let circuit_name: String = (&package.name).into(); + save_debug_artifact_to_file(&debug_artifact, &circuit_name, circuit_dir); } -fn save_contract( - contract: CompiledContract, - package: &Package, - circuit_dir: &Path, - output_debug: bool, -) { +fn save_contract(contract: CompiledContract, package: &Package, circuit_dir: &Path) { // TODO(#1389): I wonder if it is incorrect for nargo-core to know anything about contracts. // As can be seen here, It seems like a leaky abstraction where ContractFunctions (essentially CompiledPrograms) // are compiled via nargo-core and then the PreprocessedContract is constructed here. @@ -311,6 +276,7 @@ fn save_contract( }); let preprocessed_contract = PreprocessedContract { + noir_version: contract.noir_version, name: contract.name, backend: String::from(BACKEND_IDENTIFIER), functions: preprocessed_functions, @@ -323,13 +289,11 @@ fn save_contract( circuit_dir, ); - if output_debug { - save_debug_artifact_to_file( - &debug_artifact, - &format!("{}-{}", package.name, preprocessed_contract.name), - circuit_dir, - ); - } + save_debug_artifact_to_file( + &debug_artifact, + &format!("{}-{}", package.name, preprocessed_contract.name), + circuit_dir, + ); } /// Helper function for reporting any errors in a `CompilationResult` diff --git a/tooling/nargo_cli/src/cli/debug_cmd.rs b/tooling/nargo_cli/src/cli/debug_cmd.rs index 7d8c0dc9a15..82cd3349ec4 100644 --- a/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -52,14 +52,10 @@ pub(crate) fn run( return Ok(()); }; - let compiled_program = compile_bin_package( - &workspace, - package, - &args.compile_options, - true, - np_language, - &|opcode| opcode_support.is_opcode_supported(opcode), - )?; + let compiled_program = + compile_bin_package(&workspace, package, &args.compile_options, np_language, &|opcode| { + opcode_support.is_opcode_supported(opcode) + })?; println!("[{}] Starting debugger", package.name); let (return_value, solved_witness) = diff --git a/tooling/nargo_cli/src/cli/execute_cmd.rs b/tooling/nargo_cli/src/cli/execute_cmd.rs index c61dc6db69c..1819c9a6f06 100644 --- a/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -57,7 +57,6 @@ pub(crate) fn run( &workspace, package, &args.compile_options, - false, np_language, &|opcode| opcode_support.is_opcode_supported(opcode), )?; diff --git a/tooling/nargo_cli/src/cli/fs/program.rs b/tooling/nargo_cli/src/cli/fs/program.rs index 377786627be..e82f2d55264 100644 --- a/tooling/nargo_cli/src/cli/fs/program.rs +++ b/tooling/nargo_cli/src/cli/fs/program.rs @@ -60,3 +60,14 @@ pub(crate) fn read_program_from_file>( Ok(program) } + +pub(crate) fn read_debug_artifact_from_file>( + debug_artifact_path: P, +) -> Result { + let input_string = std::fs::read(&debug_artifact_path) + .map_err(|_| FilesystemError::PathNotValid(debug_artifact_path.as_ref().into()))?; + let program = serde_json::from_slice(&input_string) + .map_err(|err| FilesystemError::ProgramSerializationError(err.to_string()))?; + + Ok(program) +} diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index e55b1b7886f..50021e842c4 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -63,7 +63,6 @@ pub(crate) fn run( np_language, &opcode_support, &args.compile_options, - false, )?; let program_info = binary_packages diff --git a/tooling/nargo_cli/src/cli/init_cmd.rs b/tooling/nargo_cli/src/cli/init_cmd.rs index 6dc7b9bd98e..9d7700a6598 100644 --- a/tooling/nargo_cli/src/cli/init_cmd.rs +++ b/tooling/nargo_cli/src/cli/init_cmd.rs @@ -2,10 +2,11 @@ use crate::backends::Backend; use crate::errors::CliError; use super::fs::{create_named_dir, write_to_file}; -use super::{NargoConfig, CARGO_PKG_VERSION}; +use super::NargoConfig; use clap::Args; use nargo::constants::{PKG_FILE, SRC_DIR}; use nargo::package::PackageType; +use noirc_driver::NOIRC_VERSION; use noirc_frontend::graph::CrateName; use std::path::PathBuf; @@ -72,7 +73,7 @@ pub(crate) fn initialize_project( name = "{package_name}" type = "{package_type}" authors = [""] -compiler_version = "{CARGO_PKG_VERSION}" +compiler_version = "{NOIRC_VERSION}" [dependencies]"# ); diff --git a/tooling/nargo_cli/src/cli/mod.rs b/tooling/nargo_cli/src/cli/mod.rs index a0ef778e1a5..8d22fb1b204 100644 --- a/tooling/nargo_cli/src/cli/mod.rs +++ b/tooling/nargo_cli/src/cli/mod.rs @@ -1,6 +1,7 @@ use clap::{Args, Parser, Subcommand}; use const_format::formatcp; use nargo_toml::find_package_root; +use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; use std::path::PathBuf; use color_eyre::eyre; @@ -26,10 +27,15 @@ mod verify_cmd; const GIT_HASH: &str = env!("GIT_COMMIT"); const IS_DIRTY: &str = env!("GIT_DIRTY"); -const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); - -static VERSION_STRING: &str = - formatcp!("{} (git version hash: {}, is dirty: {})", CARGO_PKG_VERSION, GIT_HASH, IS_DIRTY); +const NARGO_VERSION: &str = env!("CARGO_PKG_VERSION"); + +static VERSION_STRING: &str = formatcp!( + "version = {}\nnoirc version = {}\n(git version hash: {}, is dirty: {})", + NARGO_VERSION, + NOIR_ARTIFACT_VERSION_STRING, + GIT_HASH, + IS_DIRTY +); #[derive(Parser, Debug)] #[command(name="nargo", author, version=VERSION_STRING, about, long_about = None)] diff --git a/tooling/nargo_cli/src/cli/prove_cmd.rs b/tooling/nargo_cli/src/cli/prove_cmd.rs index 5571117e2d4..af300b7ebe0 100644 --- a/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -59,7 +59,6 @@ pub(crate) fn run( &workspace, package, &args.compile_options, - false, np_language, &|opcode| opcode_support.is_opcode_supported(opcode), )?; diff --git a/tooling/nargo_cli/src/cli/verify_cmd.rs b/tooling/nargo_cli/src/cli/verify_cmd.rs index a5a39e9aef9..6ae2b78fd0c 100644 --- a/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -50,7 +50,6 @@ pub(crate) fn run( &workspace, package, &args.compile_options, - false, np_language, &|opcode| opcode_support.is_opcode_supported(opcode), )?; diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/acir.gz deleted file mode 100644 index 090578ca4e3..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/witness.gz deleted file mode 100644 index 16880cedea2..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_547/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_579/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/conditional_regression_to_bits/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/main_return/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/main_return/target/acir.gz deleted file mode 100644 index 4763c63284d..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/main_return/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/main_return/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/main_return/target/witness.gz deleted file mode 100644 index 8083b6de7e4..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/main_return/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/references_aliasing/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/acir.gz index 3c21d9a4bf8..19713609a3e 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/witness.gz index 40ca3d3f63f..6bedf3922b0 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha2_blocks/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/acir.gz index b285f9c24e5..58bde76d70f 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/acir.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/acir.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/witness.gz index 66d8125a852..746c6fc56a2 100644 Binary files a/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/witness.gz and b/tooling/nargo_cli/tests/acir_artifacts/sha2_byte/target/witness.gz differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/acir.gz deleted file mode 100644 index e908711b098..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/witness.gz deleted file mode 100644 index a8e277ea795..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/simple_array_param/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_allowed_item_name_matches/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_associated_member_names_clashes/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/acir.gz deleted file mode 100644 index b3a99dacb66..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/witness.gz deleted file mode 100644 index c3b8e758662..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_default_implementation/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_function_calls/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_multi_module_test/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/acir.gz deleted file mode 100644 index b3a99dacb66..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/witness.gz deleted file mode 100644 index c3b8e758662..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_override_implementation/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_self/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/acir.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/acir.gz deleted file mode 100644 index 2639a2e0809..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/acir.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/witness.gz b/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/tooling/nargo_cli/tests/acir_artifacts/trait_where_clause/target/witness.gz and /dev/null differ diff --git a/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/Nargo.toml b/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/Nargo.toml new file mode 100644 index 00000000000..99340cf80b5 --- /dev/null +++ b/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "simple_contract" +type = "contract" +authors = [""] +compiler_version = "0.1" + +[dependencies] + diff --git a/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/src/main.nr b/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/src/main.nr new file mode 100644 index 00000000000..fa04e0d3e7b --- /dev/null +++ b/tooling/nargo_cli/tests/compile_success_contract/contract_with_impl/src/main.nr @@ -0,0 +1,8 @@ + +contract Foo { + struct T { x: [Field] } + + impl T { + fn t(self){} + } +} diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_547/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_547/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_547/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_547/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_547/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_547/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_547/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_579/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_579/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_579/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_579/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_579/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_579/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_579/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/conditional_regression_to_bits/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/conditional_regression_to_bits/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/main_return/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/main_return/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/main_return/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/main_return/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/main_return/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/main_return/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/main_return/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/main_return/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/main_return/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/main_return/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/main_return/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/main_return/src/main.nr diff --git a/tooling/nargo_cli/tests/compile_success_empty/references_aliasing/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/references_aliasing/src/main.nr index 4582444c8f7..02057732f35 100644 --- a/tooling/nargo_cli/tests/compile_success_empty/references_aliasing/src/main.nr +++ b/tooling/nargo_cli/tests/compile_success_empty/references_aliasing/src/main.nr @@ -1,10 +1,29 @@ -fn increment(mut r: &mut Field) { - *r = *r + 1; -} - fn main() { let mut x = 100; let mut xref = &mut x; increment(xref); assert(*xref == 101); + + regression_2445(); +} + +fn increment(mut r: &mut Field) { + *r = *r + 1; +} + +// If aliasing within arrays and constant folding within the mem2reg pass aren't +// handled, we'll fail to optimize out all the references in this function. +fn regression_2445() { + let mut var = 0; + let ref = &mut &mut var; + + let mut array = [ref, ref]; + + **array[0] = 1; + **array[1] = 2; + + assert(var == 2); + assert(**ref == 2); + assert(**array[0] == 2); + assert(**array[1] == 2); } diff --git a/tooling/nargo_cli/tests/execution_success/simple_array_param/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/simple_array_param/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/simple_array_param/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/simple_array_param/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/simple_array_param/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/simple_array_param/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/simple_array_param/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/simple_array_param/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/simple_array_param/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/simple_array_param/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/simple_array_param/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/simple_array_param/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/references_aliasing/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/references_aliasing/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_allowed_item_name_matches/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_allowed_item_name_matches/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_associated_member_names_clashes/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_default_implementation/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_default_implementation/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_default_implementation/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_default_implementation/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_default_implementation/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_default_implementation/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_default_implementation/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_function_calls/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_function_calls/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_associated_member_names_clashes/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_function_calls/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_function_calls/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_function_calls/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_function_calls/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_function_calls/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module1.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module1.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module1.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module1.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module2.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module2.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module2.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module2.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module3.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module3.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module3.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module3.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module4.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module4.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module4.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module4.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module5.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module5.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module5.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module5.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module6.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module6.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_multi_module_test/src/module6.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_multi_module_test/src/module6.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_override_implementation/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_override_implementation/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_override_implementation/Prover.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_override_implementation/Prover.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/Prover.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_override_implementation/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_override_implementation/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_override_implementation/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_self/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_self/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_self/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_self/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_self/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_self/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_self/trait_self/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_self/trait_self/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_self/trait_self/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_self/trait_self/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_self/trait_self/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_self/trait_self/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_where_clause/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/Nargo.toml similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_where_clause/Nargo.toml rename to tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/Nargo.toml diff --git a/tooling/nargo_cli/tests/execution_success/trait_where_clause/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/src/main.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_where_clause/src/main.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/src/main.nr diff --git a/tooling/nargo_cli/tests/execution_success/trait_where_clause/src/the_trait.nr b/tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/src/the_trait.nr similarity index 100% rename from tooling/nargo_cli/tests/execution_success/trait_where_clause/src/the_trait.nr rename to tooling/nargo_cli/tests/compile_success_empty/trait_where_clause/src/the_trait.nr diff --git a/tooling/nargo_cli/tests/execution_success/references_aliasing/Nargo.toml b/tooling/nargo_cli/tests/execution_success/references_aliasing/Nargo.toml deleted file mode 100644 index b95c3998483..00000000000 --- a/tooling/nargo_cli/tests/execution_success/references_aliasing/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "references_aliasing" -type = "bin" -authors = [""] -compiler_version = "0.5.1" - -[dependencies] diff --git a/tooling/nargo_cli/tests/execution_success/references_aliasing/src/main.nr b/tooling/nargo_cli/tests/execution_success/references_aliasing/src/main.nr deleted file mode 100644 index 02057732f35..00000000000 --- a/tooling/nargo_cli/tests/execution_success/references_aliasing/src/main.nr +++ /dev/null @@ -1,29 +0,0 @@ -fn main() { - let mut x = 100; - let mut xref = &mut x; - increment(xref); - assert(*xref == 101); - - regression_2445(); -} - -fn increment(mut r: &mut Field) { - *r = *r + 1; -} - -// If aliasing within arrays and constant folding within the mem2reg pass aren't -// handled, we'll fail to optimize out all the references in this function. -fn regression_2445() { - let mut var = 0; - let ref = &mut &mut var; - - let mut array = [ref, ref]; - - **array[0] = 1; - **array[1] = 2; - - assert(var == 2); - assert(**ref == 2); - assert(**array[0] == 2); - assert(**array[1] == 2); -} diff --git a/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/Prover.toml b/tooling/nargo_cli/tests/execution_success/trait_multi_module_test/Prover.toml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tooling/nargo_cli/tests/gates_report.sh b/tooling/nargo_cli/tests/gates_report.sh new file mode 100755 index 00000000000..e06e6812e9d --- /dev/null +++ b/tooling/nargo_cli/tests/gates_report.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +# These tests are incompatible with gas reporting +excluded_dirs=("workspace" "workspace_default_member") + +# These tests cause failures in CI with a stack overflow for some reason. +ci_excluded_dirs=("eddsa") + +current_dir=$(pwd) +base_path="$current_dir/execution_success" +test_dirs=$(ls $base_path) + +# We generate a Noir workspace which contains all of the test cases +# This allows us to generate a gates report using `nargo info` for all of them at once. + +echo "[workspace]" > Nargo.toml +echo "members = [" >> Nargo.toml + +for dir in $test_dirs; do + if [[ " ${excluded_dirs[@]} " =~ " ${dir} " ]]; then + continue + fi + + if [[ ${CI-false} = "true" ]] && [[ " ${ci_excluded_dirs[@]} " =~ " ${dir} " ]]; then + continue + fi + + echo " \"execution_success/$dir\"," >> Nargo.toml +done + +echo "]" >> Nargo.toml + +nargo info --json > gates_report.json + +rm Nargo.toml diff --git a/tooling/nargo_fmt/src/config.rs b/tooling/nargo_fmt/src/config.rs index 1514937caff..dd57778da92 100644 --- a/tooling/nargo_fmt/src/config.rs +++ b/tooling/nargo_fmt/src/config.rs @@ -46,7 +46,8 @@ config! { tab_spaces: usize, 4, "Number of spaces per tab"; remove_nested_parens: bool, true, "Remove nested parens"; short_array_element_width_threshold: usize, 10, "Width threshold for an array element to be considered short"; - array_width: usize, 60, "Maximum width of an array literal before falling back to vertical formatting"; + array_width: usize, 100, "Maximum width of an array literal before falling back to vertical formatting"; + single_line_if_else_max_width: usize, 100, "Maximum line length for single line if-else expressions"; } impl Config { diff --git a/tooling/nargo_fmt/src/lib.rs b/tooling/nargo_fmt/src/lib.rs index 887e71be735..3e8ee570c09 100644 --- a/tooling/nargo_fmt/src/lib.rs +++ b/tooling/nargo_fmt/src/lib.rs @@ -20,9 +20,8 @@ /// in both placement and content during the formatting process. mod config; pub mod errors; -#[macro_use] -mod visitor; mod utils; +mod visitor; use noirc_frontend::ParsedModule; use visitor::FmtVisitor; diff --git a/tooling/nargo_fmt/src/utils.rs b/tooling/nargo_fmt/src/utils.rs index 4bea21be939..68c6b8bd1e3 100644 --- a/tooling/nargo_fmt/src/utils.rs +++ b/tooling/nargo_fmt/src/utils.rs @@ -2,7 +2,7 @@ use crate::visitor::FmtVisitor; use noirc_frontend::hir::resolution::errors::Span; use noirc_frontend::lexer::Lexer; use noirc_frontend::token::Token; -use noirc_frontend::Expression; +use noirc_frontend::{Expression, Ident}; pub(crate) fn recover_comment_removed(original: &str, new: String) -> String { if changed_comment_content(original, &new) { @@ -46,19 +46,15 @@ impl Expr { } } -pub(crate) struct Exprs<'me> { +pub(crate) struct Exprs<'me, T> { pub(crate) visitor: &'me FmtVisitor<'me>, - pub(crate) elements: std::iter::Peekable>, + pub(crate) elements: std::iter::Peekable>, pub(crate) last_position: u32, pub(crate) end_position: u32, } -impl<'me> Exprs<'me> { - pub(crate) fn new( - visitor: &'me FmtVisitor<'me>, - span: Span, - elements: Vec, - ) -> Self { +impl<'me, T: Item> Exprs<'me, T> { + pub(crate) fn new(visitor: &'me FmtVisitor<'me>, span: Span, elements: Vec) -> Self { Self { visitor, last_position: span.start() + 1, /*(*/ @@ -68,33 +64,33 @@ impl<'me> Exprs<'me> { } } -impl Iterator for Exprs<'_> { +impl Iterator for Exprs<'_, T> { type Item = Expr; fn next(&mut self) -> Option { let element = self.elements.next()?; - let element_span = element.span; + let element_span = element.span(); let start = self.last_position; let end = element_span.start(); let is_last = self.elements.peek().is_none(); - let next_start = self.elements.peek().map_or(self.end_position, |expr| expr.span.start()); + let next_start = self.elements.peek().map_or(self.end_position, |expr| expr.start()); let (leading, different_line) = self.leading(start, end); - let expr = self.visitor.format_expr(element); + let expr = element.format(self.visitor); let trailing = self.trailing(element_span.end(), next_start, is_last); Expr { leading, value: expr, trailing, different_line }.into() } } -impl<'me> Exprs<'me> { +impl<'me, T> Exprs<'me, T> { pub(crate) fn leading(&mut self, start: u32, end: u32) -> (String, bool) { let mut different_line = false; - let leading = slice!(self.visitor, start, end); - let leading_trimmed = slice!(self.visitor, start, end).trim(); + let leading = self.visitor.slice(start..end); + let leading_trimmed = leading.trim(); let starts_with_block_comment = leading_trimmed.starts_with("/*"); let ends_with_block_comment = leading_trimmed.ends_with("*/"); @@ -114,7 +110,7 @@ impl<'me> Exprs<'me> { } pub(crate) fn trailing(&mut self, start: u32, end: u32, is_last: bool) -> String { - let slice = slice!(self.visitor, start, end); + let slice = self.visitor.slice(start..end); let comment_end = find_comment_end(slice, is_last); let trailing = slice[..comment_end].trim_matches(',').trim(); self.last_position = start + (comment_end as u32); @@ -201,3 +197,47 @@ fn comment_len(comment: &str) -> usize { } } } + +pub(crate) trait Item { + fn span(&self) -> Span; + + fn format(self, visitor: &FmtVisitor) -> String; + + fn start(&self) -> u32 { + self.span().start() + } + + fn end(&self) -> u32 { + self.span().end() + } +} + +impl Item for Expression { + fn span(&self) -> Span { + self.span + } + + fn format(self, visitor: &FmtVisitor) -> String { + visitor.format_subexpr(self) + } +} + +impl Item for (Ident, Expression) { + fn span(&self) -> Span { + let (name, value) = self; + (name.span().start()..value.span.end()).into() + } + + fn format(self, visitor: &FmtVisitor) -> String { + let (name, expr) = self; + + let name = name.0.contents; + let expr = visitor.format_subexpr(expr); + + if name == expr { + name + } else { + format!("{name}: {expr}") + } + } +} diff --git a/tooling/nargo_fmt/src/visitor.rs b/tooling/nargo_fmt/src/visitor.rs index f357fb2f12b..d1c87d311e7 100644 --- a/tooling/nargo_fmt/src/visitor.rs +++ b/tooling/nargo_fmt/src/visitor.rs @@ -1,18 +1,10 @@ -/// A macro to create a slice from a given data source, helping to avoid borrow checker errors. -#[macro_export] -macro_rules! slice { - ($this:expr, $start:expr, $end:expr) => { - &$this.source[$start as usize..$end as usize] - }; -} - mod expr; mod item; mod stmt; -use noirc_frontend::hir::resolution::errors::Span; +use noirc_frontend::{hir::resolution::errors::Span, token::Token}; -use crate::config::Config; +use crate::{config::Config, utils::FindToken}; pub(crate) struct FmtVisitor<'me> { config: &'me Config, @@ -33,6 +25,20 @@ impl<'me> FmtVisitor<'me> { } } + pub(crate) fn slice(&self, span: impl Into) -> &'me str { + let span = span.into(); + &self.source[span.start() as usize..span.end() as usize] + } + + fn span_before(&self, span: impl Into, token: Token) -> Span { + let span = span.into(); + + let slice = self.slice(span); + let offset = slice.find_token(token).unwrap(); + + (span.start() + offset..span.end()).into() + } + fn shape(&self) -> Shape { Shape { width: self.config.max_width.saturating_sub(self.indent.width()), @@ -110,7 +116,7 @@ impl<'me> FmtVisitor<'me> { return; } - let slice = slice!(self, start, end); + let slice = self.slice(start..end); self.last_position = end; if slice.trim().is_empty() && !self.at_start() { @@ -147,7 +153,7 @@ impl<'me> FmtVisitor<'me> { } pub(crate) fn format_comment(&self, span: Span) -> String { - let slice = slice!(self, span.start(), span.end()).trim(); + let slice = self.slice(span).trim(); let pos = slice.find('/'); if !slice.is_empty() && pos.is_some() { @@ -158,7 +164,7 @@ impl<'me> FmtVisitor<'me> { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] struct Indent { block_indent: usize, } @@ -191,3 +197,9 @@ struct Shape { width: usize, indent: Indent, } + +#[derive(PartialEq, Eq, Debug)] +pub(crate) enum ExpressionType { + Statement, + SubExpression, +} diff --git a/tooling/nargo_fmt/src/visitor/expr.rs b/tooling/nargo_fmt/src/visitor/expr.rs index 8d996276a10..dcf4dbbd3b1 100644 --- a/tooling/nargo_fmt/src/visitor/expr.rs +++ b/tooling/nargo_fmt/src/visitor/expr.rs @@ -1,29 +1,35 @@ -use std::ops::Range; - use noirc_frontend::{ - hir::resolution::errors::Span, token::Token, ArrayLiteral, BlockExpression, Expression, - ExpressionKind, Literal, Statement, UnaryOp, + hir::resolution::errors::Span, token::Token, ArrayLiteral, BlockExpression, + ConstructorExpression, Expression, ExpressionKind, IfExpression, Literal, Statement, + StatementKind, UnaryOp, }; -use super::{FmtVisitor, Shape}; +use super::{ExpressionType, FmtVisitor, Indent, Shape}; use crate::{ - utils::{self, Expr, FindToken}, + utils::{self, Expr, FindToken, Item}, Config, }; impl FmtVisitor<'_> { - pub(crate) fn visit_expr(&mut self, expr: Expression) { + pub(crate) fn visit_expr(&mut self, expr: Expression, expr_type: ExpressionType) { let span = expr.span; - let rewrite = self.format_expr(expr); - let rewrite = - utils::recover_comment_removed(slice!(self, span.start(), span.end()), rewrite); + let rewrite = self.format_expr(expr, expr_type); + let rewrite = utils::recover_comment_removed(self.slice(span), rewrite); self.push_rewrite(rewrite, span); self.last_position = span.end(); } - pub(crate) fn format_expr(&self, Expression { kind, mut span }: Expression) -> String { + pub(crate) fn format_subexpr(&self, expression: Expression) -> String { + self.format_expr(expression, ExpressionType::SubExpression) + } + + pub(crate) fn format_expr( + &self, + Expression { kind, mut span }: Expression, + expr_type: ExpressionType, + ) -> String { match kind { ExpressionKind::Block(block) => { let mut visitor = self.fork(); @@ -44,55 +50,50 @@ impl FmtVisitor<'_> { } }; - format!("{op}{}", self.format_expr(prefix.rhs)) + format!("{op}{}", self.format_subexpr(prefix.rhs)) } ExpressionKind::Cast(cast) => { - format!("{} as {}", self.format_expr(cast.lhs), cast.r#type) + format!("{} as {}", self.format_subexpr(cast.lhs), cast.r#type) } ExpressionKind::Infix(infix) => { format!( "{} {} {}", - self.format_expr(infix.lhs), + self.format_subexpr(infix.lhs), infix.operator.contents.as_string(), - self.format_expr(infix.rhs) + self.format_subexpr(infix.rhs) ) } ExpressionKind::Call(call_expr) => { - let span = call_expr.func.span.end()..span.end(); - let span = - skip_useless_tokens(Token::LeftParen, slice!(self, span.start, span.end), span); + let args_span = + self.span_before(call_expr.func.span.end()..span.end(), Token::LeftParen); - let callee = self.format_expr(*call_expr.func); - let args = format_parens(self.fork(), false, call_expr.arguments, span); + let callee = self.format_subexpr(*call_expr.func); + let args = format_parens(self.fork(), false, call_expr.arguments, args_span); format!("{callee}{args}") } ExpressionKind::MethodCall(method_call_expr) => { - let span = method_call_expr.method_name.span().end()..span.end(); - let span = - skip_useless_tokens(Token::LeftParen, slice!(self, span.start, span.end), span); + let args_span = self.span_before( + method_call_expr.method_name.span().end()..span.end(), + Token::LeftParen, + ); - let object = self.format_expr(method_call_expr.object); + let object = self.format_subexpr(method_call_expr.object); let method = method_call_expr.method_name.to_string(); - let args = format_parens(self.fork(), false, method_call_expr.arguments, span); + let args = format_parens(self.fork(), false, method_call_expr.arguments, args_span); format!("{object}.{method}{args}") } ExpressionKind::MemberAccess(member_access_expr) => { - let lhs_str = self.format_expr(member_access_expr.lhs); + let lhs_str = self.format_subexpr(member_access_expr.lhs); format!("{}.{}", lhs_str, member_access_expr.rhs) } ExpressionKind::Index(index_expr) => { - let span = index_expr.collection.span.end()..span.end(); + let index_span = self + .span_before(index_expr.collection.span.end()..span.end(), Token::LeftBracket); - let span = skip_useless_tokens( - Token::LeftBracket, - slice!(self, span.start, span.end), - span, - ); - - let collection = self.format_expr(index_expr.collection); - let index = format_brackets(self.fork(), false, vec![index_expr.index], span); + let collection = self.format_subexpr(index_expr.collection); + let index = format_brackets(self.fork(), false, vec![index_expr.index], index_span); format!("{collection}{index}") } @@ -101,11 +102,11 @@ impl FmtVisitor<'_> { } ExpressionKind::Literal(literal) => match literal { Literal::Integer(_) | Literal::Bool(_) | Literal::Str(_) | Literal::FmtStr(_) => { - slice!(self, span.start(), span.end()).to_string() + self.slice(span).to_string() } Literal::Array(ArrayLiteral::Repeated { repeated_element, length }) => { - let repeated = self.format_expr(*repeated_element); - let length = self.format_expr(*length); + let repeated = self.format_subexpr(*repeated_element); + let length = self.format_subexpr(*length); format!("[{repeated}; {length}]") } @@ -139,7 +140,7 @@ impl FmtVisitor<'_> { } if !leading.contains("//") && !trailing.contains("//") { - let sub_expr = self.format_expr(*sub_expr); + let sub_expr = self.format_subexpr(*sub_expr); format!("({leading}{sub_expr}{trailing})") } else { let mut visitor = self.fork(); @@ -148,7 +149,7 @@ impl FmtVisitor<'_> { visitor.indent.block_indent(self.config); let nested_indent = visitor.indent.to_string_with_newline(); - let sub_expr = visitor.format_expr(*sub_expr); + let sub_expr = visitor.format_subexpr(*sub_expr); let mut result = String::new(); result.push('('); @@ -172,11 +173,111 @@ impl FmtVisitor<'_> { result } } - // TODO: - _expr => slice!(self, span.start(), span.end()).to_string(), + ExpressionKind::Constructor(constructor) => { + let type_name = self.slice(constructor.type_name.span()); + let fields_span = self + .span_before(constructor.type_name.span().end()..span.end(), Token::LeftBrace); + + self.format_struct_lit(type_name, fields_span, *constructor) + } + ExpressionKind::If(if_expr) => { + let allow_single_line = expr_type == ExpressionType::SubExpression; + + if allow_single_line { + let mut visitor = self.fork(); + visitor.indent = Indent::default(); + if let Some(line) = visitor.format_if_single_line(*if_expr.clone()) { + return line; + } + } + + self.format_if(*if_expr) + } + _ => self.slice(span).to_string(), } } + fn format_if(&self, if_expr: IfExpression) -> String { + let condition_str = self.format_subexpr(if_expr.condition); + let consequence_str = self.format_subexpr(if_expr.consequence); + + let mut result = format!("if {condition_str} {consequence_str}"); + + if let Some(alternative) = if_expr.alternative { + let alternative = if let Some(ExpressionKind::If(if_expr)) = + extract_simple_expr(alternative.clone()).map(|expr| expr.kind) + { + self.format_if(*if_expr) + } else { + self.format_expr(alternative, ExpressionType::Statement) + }; + + result.push_str(" else "); + result.push_str(&alternative); + }; + + result + } + + fn format_if_single_line(&self, if_expr: IfExpression) -> Option { + let condition_str = self.format_subexpr(if_expr.condition); + let consequence_str = self.format_subexpr(extract_simple_expr(if_expr.consequence)?); + + let if_str = if let Some(alternative) = if_expr.alternative { + let alternative_str = if let Some(ExpressionKind::If(_)) = + extract_simple_expr(alternative.clone()).map(|expr| expr.kind) + { + return None; + } else { + self.format_expr(extract_simple_expr(alternative)?, ExpressionType::Statement) + }; + + format!("if {} {{ {} }} else {{ {} }}", condition_str, consequence_str, alternative_str) + } else { + format!("if {{{}}} {{{}}}", condition_str, consequence_str) + }; + + (if_str.len() <= self.config.single_line_if_else_max_width).then_some(if_str) + } + + fn format_struct_lit( + &self, + type_name: &str, + fields_span: Span, + constructor: ConstructorExpression, + ) -> String { + let fields = { + let mut visitor = self.fork(); + + visitor.indent.block_indent(visitor.config); + + let nested_indent = visitor.shape(); + let exprs: Vec<_> = + utils::Exprs::new(&visitor, fields_span, constructor.fields).collect(); + let exprs = format_exprs( + visitor.config, + Tactic::HorizontalVertical, + false, + exprs, + nested_indent, + ); + + visitor.indent.block_unindent(visitor.config); + + if exprs.contains('\n') { + format!( + "{}{exprs}{}", + nested_indent.indent.to_string_with_newline(), + visitor.shape().indent.to_string_with_newline() + ) + } else { + format!(" {exprs} ") + } + }; + + format!("{type_name} {{{fields}}}") + } + pub(crate) fn visit_block( &mut self, block: BlockExpression, @@ -197,7 +298,7 @@ impl FmtVisitor<'_> { this.visit_stmts(block.0); }); - let slice = slice!(self, self.last_position, block_span.end() - 1).trim_end(); + let slice = self.slice(self.last_position..block_span.end() - 1).trim_end(); self.push_str(slice); self.last_position = block_span.end(); @@ -211,7 +312,7 @@ impl FmtVisitor<'_> { fn trim_spaces_after_opening_brace(&mut self, block: &[Statement]) { if let Some(first_stmt) = block.first() { - let slice = slice!(self, self.last_position, first_stmt.span.start()); + let slice = self.slice(self.last_position..first_stmt.span.start()); let len = slice.chars().take_while(|ch| ch.is_whitespace()).collect::().rfind('\n'); self.last_position += len.unwrap_or(0) as u32; @@ -219,7 +320,7 @@ impl FmtVisitor<'_> { } fn visit_empty_block(&mut self, block_span: Span, should_indent: bool) { - let slice = slice!(self, block_span.start(), block_span.end()); + let slice = self.slice(block_span); let comment_str = slice[1..slice.len() - 1].trim(); let block_str = if comment_str.is_empty() { "{}".to_string() @@ -237,24 +338,24 @@ impl FmtVisitor<'_> { } } -fn format_expr_seq( +fn format_expr_seq( prefix: &str, - sufix: &str, + suffix: &str, mut visitor: FmtVisitor, trailing_comma: bool, - exprs: Vec, + exprs: Vec, span: Span, - limit: Option, + tactic: Tactic, ) -> String { visitor.indent.block_indent(visitor.config); let nested_indent = visitor.shape(); let exprs: Vec<_> = utils::Exprs::new(&visitor, span, exprs).collect(); - let exprs = format_exprs(visitor.config, trailing_comma, exprs, nested_indent, limit); + let exprs = format_exprs(visitor.config, tactic, trailing_comma, exprs, nested_indent); visitor.indent.block_unindent(visitor.config); - wrap_exprs(prefix, sufix, exprs, nested_indent, visitor.shape()) + wrap_exprs(prefix, suffix, exprs, nested_indent, visitor.shape()) } fn format_brackets( @@ -264,7 +365,15 @@ fn format_brackets( span: Span, ) -> String { let array_width = visitor.config.array_width; - format_expr_seq("[", "]", visitor, trailing_comma, exprs, span, array_width.into()) + format_expr_seq( + "[", + "]", + visitor, + trailing_comma, + exprs, + span, + Tactic::LimitedHorizontalVertical(array_width), + ) } fn format_parens( @@ -273,20 +382,20 @@ fn format_parens( exprs: Vec, span: Span, ) -> String { - format_expr_seq("(", ")", visitor, trailing_comma, exprs, span, None) + format_expr_seq("(", ")", visitor, trailing_comma, exprs, span, Tactic::Horizontal) } fn format_exprs( config: &Config, + tactic: Tactic, trailing_comma: bool, exprs: Vec, shape: Shape, - limit: Option, ) -> String { let mut result = String::new(); let indent_str = shape.indent.to_string(); - let tactic = Tactic::of(&exprs, config.short_array_element_width_threshold, limit); + let tactic = tactic.definitive(&exprs, config.short_array_element_width_threshold); let mut exprs = exprs.into_iter().enumerate().peekable(); let mut line_len = 0; let mut prev_expr_trailing_comment = false; @@ -297,14 +406,16 @@ fn format_exprs( let separate_len = usize::from(separate); match tactic { - Tactic::Vertical if !is_first && !expr.value.is_empty() && !result.is_empty() => { + DefinitiveTactic::Vertical + if !is_first && !expr.value.is_empty() && !result.is_empty() => + { result.push('\n'); result.push_str(&indent_str); } - Tactic::Horizontal if !is_first => { + DefinitiveTactic::Horizontal if !is_first => { result.push(' '); } - Tactic::Mixed => { + DefinitiveTactic::Mixed => { let total_width = expr.total_width() + separate_len; if line_len > 0 && line_len + 1 + total_width > shape.width @@ -335,7 +446,7 @@ fn format_exprs( result.push_str(&expr.value); - if tactic == Tactic::Horizontal { + if tactic == DefinitiveTactic::Horizontal { result.push_str(&expr.trailing); } @@ -343,7 +454,7 @@ fn format_exprs( result.push(','); } - if tactic != Tactic::Horizontal { + if tactic != DefinitiveTactic::Horizontal { prev_expr_trailing_comment = !expr.trailing.is_empty(); if !expr.different_line && !expr.trailing.is_empty() { @@ -359,7 +470,7 @@ fn format_exprs( fn wrap_exprs( prefix: &str, - sufix: &str, + suffix: &str, exprs: String, nested_shape: Shape, shape: Shape, @@ -380,46 +491,84 @@ fn wrap_exprs( String::new() }; - format!("{prefix}{exprs}{trailing_newline}{sufix}") + format!("{prefix}{exprs}{trailing_newline}{suffix}") } else { let nested_indent_str = nested_shape.indent.to_string_with_newline(); - let indent_str = shape.indent.to_string(); + let indent_str = shape.indent.to_string_with_newline(); - format!("{prefix}{nested_indent_str}{exprs}{indent_str}{sufix}") + format!("{prefix}{nested_indent_str}{exprs}{indent_str}{suffix}") } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(PartialEq, Eq)] enum Tactic { - Vertical, Horizontal, + HorizontalVertical, + LimitedHorizontalVertical(usize), Mixed, } impl Tactic { - fn of(exprs: &[Expr], max_width: usize, limit: Option) -> Self { - let mut tactic = if exprs.iter().any(|item| { - has_single_line_comment(&item.leading) || has_single_line_comment(&item.trailing) - }) { - Tactic::Vertical - } else { - Tactic::Horizontal + fn definitive( + self, + exprs: &[Expr], + short_array_element_width_threshold: usize, + ) -> DefinitiveTactic { + let tactic = || { + let has_single_line_comment = exprs.iter().any(|item| { + has_single_line_comment(&item.leading) || has_single_line_comment(&item.trailing) + }); + + let limit = match self { + _ if has_single_line_comment => return DefinitiveTactic::Vertical, + + Tactic::Horizontal => return DefinitiveTactic::Horizontal, + Tactic::LimitedHorizontalVertical(limit) => limit, + Tactic::HorizontalVertical | Tactic::Mixed => 100, + }; + + let (sep_count, total_width): (usize, usize) = exprs + .iter() + .map(|expr| expr.total_width()) + .fold((0, 0), |(sep_count, total_width), width| { + (sep_count + 1, total_width + width) + }); + + let total_sep_len = sep_count.saturating_sub(1); + let real_total = total_width + total_sep_len; + + if real_total <= limit && !exprs.iter().any(|expr| expr.is_multiline()) { + DefinitiveTactic::Horizontal + } else if self == Tactic::Mixed { + DefinitiveTactic::Mixed + } else { + DefinitiveTactic::Vertical + } }; - if tactic == Tactic::Vertical && no_long_exprs(exprs, max_width) { - tactic = Tactic::Mixed; - } + tactic().reduce(exprs, short_array_element_width_threshold) + } +} - if let Some(limit) = limit { - let total_width: usize = exprs.iter().map(|expr| expr.total_width()).sum(); - if total_width <= limit && !exprs.iter().any(|expr| expr.is_multiline()) { - tactic = Tactic::Horizontal; - } else { - tactic = Tactic::Mixed; +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum DefinitiveTactic { + Vertical, + Horizontal, + Mixed, +} + +impl DefinitiveTactic { + fn reduce(self, exprs: &[Expr], short_array_element_width_threshold: usize) -> Self { + match self { + DefinitiveTactic::Vertical + if no_long_exprs(exprs, short_array_element_width_threshold) => + { + DefinitiveTactic::Mixed + } + DefinitiveTactic::Vertical | DefinitiveTactic::Horizontal | DefinitiveTactic::Mixed => { + self } } - - tactic } } @@ -427,12 +576,18 @@ fn has_single_line_comment(slice: &str) -> bool { slice.trim_start().starts_with("//") } -fn skip_useless_tokens(token: Token, slice: &str, mut span: Range) -> Span { - let offset = slice.find_token(token).unwrap(); - span.start += offset; - span.into() -} - fn no_long_exprs(exprs: &[Expr], max_width: usize) -> bool { exprs.iter().all(|expr| expr.value.len() <= max_width) } + +fn extract_simple_expr(expr: Expression) -> Option { + if let ExpressionKind::Block(mut block) = expr.kind { + if block.len() == 1 { + if let StatementKind::Expression(expr) = block.pop().unwrap() { + return expr.into(); + } + } + } + + None +} diff --git a/tooling/nargo_fmt/src/visitor/item.rs b/tooling/nargo_fmt/src/visitor/item.rs index 1e32ab22747..09031082fa3 100644 --- a/tooling/nargo_fmt/src/visitor/item.rs +++ b/tooling/nargo_fmt/src/visitor/item.rs @@ -5,7 +5,7 @@ use noirc_frontend::{ impl super::FmtVisitor<'_> { fn format_fn_before_block(&self, func: NoirFunction, start: u32) -> (String, bool) { - let slice = slice!(self, start, func.span().start()); + let slice = self.slice(start..func.span().start()); let force_brace_newline = slice.contains("//"); (slice.trim_end().to_string(), force_brace_newline) } diff --git a/tooling/nargo_fmt/src/visitor/stmt.rs b/tooling/nargo_fmt/src/visitor/stmt.rs index d7a43db1e00..ca28c8a5c06 100644 --- a/tooling/nargo_fmt/src/visitor/stmt.rs +++ b/tooling/nargo_fmt/src/visitor/stmt.rs @@ -1,18 +1,30 @@ +use std::iter::zip; + use noirc_frontend::{Statement, StatementKind}; +use super::ExpressionType; + impl super::FmtVisitor<'_> { pub(crate) fn visit_stmts(&mut self, stmts: Vec) { - for Statement { kind, span } in stmts { + let len = stmts.len(); + + for (Statement { kind, span }, index) in zip(stmts, 1..) { + let is_last = index == len; + match kind { - StatementKind::Expression(expr) => self.visit_expr(expr), + StatementKind::Expression(expr) => self.visit_expr( + expr, + if is_last { ExpressionType::SubExpression } else { ExpressionType::Statement }, + ), StatementKind::Semi(expr) => { - self.visit_expr(expr); + self.visit_expr(expr, ExpressionType::Statement); self.push_str(";"); } StatementKind::Let(let_stmt) => { let let_str = - slice!(self, span.start(), let_stmt.expression.span.start()).trim_end(); - let expr_str = self.format_expr(let_stmt.expression); + self.slice(span.start()..let_stmt.expression.span.start()).trim_end(); + let expr_str = + self.format_expr(let_stmt.expression, ExpressionType::SubExpression); self.push_rewrite(format!("{let_str} {expr_str};"), span); } diff --git a/tooling/nargo_fmt/tests/expected/array.nr b/tooling/nargo_fmt/tests/expected/array.nr index c0ffa30a85e..fdf81d3595c 100644 --- a/tooling/nargo_fmt/tests/expected/array.nr +++ b/tooling/nargo_fmt/tests/expected/array.nr @@ -1,9 +1,29 @@ fn big_array() { - [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, - 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, - 10000000000000000, 100000000000000000, 1000000000000000000, 10000000000000000000, - 100000000000000000000, 1000000000000000000000, 10000000000000000000000, - 100000000000000000000000, 1000000000000000000000000]; + [1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000, + 100000000000000000000, + 1000000000000000000000, + 10000000000000000000000, + 100000000000000000000000, + 1000000000000000000000000]; [1, 10]; diff --git a/tooling/nargo_fmt/tests/expected/expr.nr b/tooling/nargo_fmt/tests/expected/expr.nr index c4fd1633bdb..20eb6ad547d 100644 --- a/tooling/nargo_fmt/tests/expected/expr.nr +++ b/tooling/nargo_fmt/tests/expected/expr.nr @@ -90,3 +90,33 @@ fn parenthesized() { x as Field ) } + +fn constructor() { + Point { x: 5, y: 10 }; +} + +fn if_expr() { + if true { + println("Hello :D"); + } +} + +fn return_if_expr() { + if true { 42 } else { 40 + 2 } +} + +fn return_if_expr() { + if true { + 42 + }; + + if true { 42 } else { 40 + 2 } +} + +fn if_if() { + if cond { + some(); + } else { + none(); + }.bar().baz(); +} diff --git a/tooling/nargo_fmt/tests/expected/if.nr b/tooling/nargo_fmt/tests/expected/if.nr new file mode 100644 index 00000000000..9893239750c --- /dev/null +++ b/tooling/nargo_fmt/tests/expected/if.nr @@ -0,0 +1,40 @@ +fn main() { + if false { + (); + (); + } + + if false // lone if comment + { + (); + (); + } + + let a = if 0 > 1 { 0 } else { 0 }; + + if true { + (); + } else if false { + (); + (); + } else { + (); + (); + (); + } + + if true // else-if-chain if comment + { + (); + } + else if false // else-if-chain else-if comment + { + (); + (); + } else // else-if-chain else comment + { + (); + (); + (); + } +} diff --git a/tooling/nargo_fmt/tests/expected/let.nr b/tooling/nargo_fmt/tests/expected/let.nr index 261982cf3e1..c53f43c7e65 100644 --- a/tooling/nargo_fmt/tests/expected/let.nr +++ b/tooling/nargo_fmt/tests/expected/let.nr @@ -14,4 +14,38 @@ fn let_() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let a = BigUint56 { + limbs: [ + 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + }; + + let person = Person { + first_name: "John", + last_name: "Doe", + home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345" } + }; + + let person = Person { + first_name: "John", + last_name: "Doe", + home_address: Address { + street: "123 Main St", + city: "Exampleville", + zip_code: "12345", + master: Person { + first_name: "John", + last_name: "Doe", + home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345" } + } + } + }; + + let expr = Expr { + // A boolean literal (true, false). + kind: ExprKind::Bool(true) + }; + + let expr = Expr { /*A boolean literal (true, false).*/ kind: ExprKind::Bool(true) }; } diff --git a/tooling/nargo_fmt/tests/expected/nested_if_else.nr b/tooling/nargo_fmt/tests/expected/nested_if_else.nr index 8aa120e3b18..dfd203189e8 100644 --- a/tooling/nargo_fmt/tests/expected/nested_if_else.nr +++ b/tooling/nargo_fmt/tests/expected/nested_if_else.nr @@ -1,3 +1,9 @@ fn nested_if_else() { - if false { 1 } else if false { 2 } else { 3 } + if false { + 1 + } else if false { + 2 + } else { + 3 + } } diff --git a/tooling/nargo_fmt/tests/expected/struct.nr b/tooling/nargo_fmt/tests/expected/struct.nr index f662e5757a5..6734dec68a6 100644 --- a/tooling/nargo_fmt/tests/expected/struct.nr +++ b/tooling/nargo_fmt/tests/expected/struct.nr @@ -34,11 +34,7 @@ struct MyStruct { my_nest: Nested, } fn test_struct_in_tuple(a_bool : bool,x:Field, y:Field) -> (MyStruct, bool) { - let my_struct = MyStruct { - my_bool: a_bool, - my_int: 5, - my_nest: Nested{a:x,b:y}, - }; + let my_struct = MyStruct { my_bool: a_bool, my_int: 5, my_nest: Nested { a: x, b: y } }; (my_struct, a_bool) } diff --git a/tooling/nargo_fmt/tests/input/expr.nr b/tooling/nargo_fmt/tests/input/expr.nr index 0baef877169..28ba9cb0585 100644 --- a/tooling/nargo_fmt/tests/input/expr.nr +++ b/tooling/nargo_fmt/tests/input/expr.nr @@ -99,3 +99,37 @@ fn parenthesized() { x as Field ) } + +fn constructor() { + Point{x :5, + y: 10 }; +} + +fn if_expr() { + if true { println("Hello :D"); } +} + +fn return_if_expr() { + if true { +42 +} +else +{ 40 + 2 } +} + +fn return_if_expr() { + if true {42}; + + if true { + 42 + } + else { + 40 + + 2 } +} + +fn if_if() { +if cond { some(); } else { none(); } + .bar() + .baz(); +} \ No newline at end of file diff --git a/tooling/nargo_fmt/tests/input/if.nr b/tooling/nargo_fmt/tests/input/if.nr new file mode 100644 index 00000000000..0985928396d --- /dev/null +++ b/tooling/nargo_fmt/tests/input/if.nr @@ -0,0 +1,52 @@ +fn main() { + if false + { + (); + (); + } + + if false // lone if comment + { + (); + (); + } + + + let a = + if 0 > 1 { + 0 + } + else + { + 0 + }; + + + if true + { + (); + } else if false { + (); + (); + } + else { + (); + (); + (); + } + + if true // else-if-chain if comment + { + (); + } + else if false // else-if-chain else-if comment + { + (); + (); + } else // else-if-chain else comment + { + (); + (); + (); + } +} diff --git a/tooling/nargo_fmt/tests/input/let.nr b/tooling/nargo_fmt/tests/input/let.nr index d73a6450a33..c603d44a4ad 100644 --- a/tooling/nargo_fmt/tests/input/let.nr +++ b/tooling/nargo_fmt/tests/input/let.nr @@ -12,4 +12,16 @@ fn let_() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; + + let a = BigUint56 {limbs:[1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}; + + let person = Person { first_name: "John", last_name: "Doe", home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345" } }; + + let person = Person { first_name: "John", last_name: "Doe", home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345", master: Person { first_name: "John", last_name: "Doe", home_address: Address { street: "123 Main St", city: "Exampleville", zip_code: "12345" } } } }; + + let expr = Expr {// A boolean literal (true, false). +kind: ExprKind::Bool(true), + }; + + let expr = Expr {/*A boolean literal (true, false).*/kind: ExprKind::Bool(true),}; }