diff --git a/.github/benchmark_projects.yml b/.github/benchmark_projects.yml index 3a67bf99e8d..7176bd7448e 100644 --- a/.github/benchmark_projects.yml +++ b/.github/benchmark_projects.yml @@ -1,4 +1,4 @@ -define: &AZ_COMMIT a90f08e245add379fa0257c81f8e2819beb190cb +define: &AZ_COMMIT cca90e5e655ed9a2d2bb969f034e42ac15f87439 projects: private-kernel-inner: repo: AztecProtocol/aztec-packages @@ -35,19 +35,19 @@ projects: path: noir-projects/noir-protocol-circuits/crates/rollup-base-private num_runs: 5 timeout: 15 - compilation-timeout: 10 - execution-timeout: 0.5 - compilation-memory-limit: 1100 - execution-memory-limit: 500 + compilation-timeout: 20 + execution-timeout: 1 + compilation-memory-limit: 1500 + execution-memory-limit: 650 rollup-base-public: repo: AztecProtocol/aztec-packages ref: *AZ_COMMIT path: noir-projects/noir-protocol-circuits/crates/rollup-base-public num_runs: 5 timeout: 15 - compilation-timeout: 8 - execution-timeout: 0.4 - compilation-memory-limit: 1000 + compilation-timeout: 15 + execution-timeout: 0.75 + compilation-memory-limit: 1300 execution-memory-limit: 500 rollup-block-root-empty: repo: AztecProtocol/aztec-packages @@ -73,7 +73,7 @@ projects: path: noir-projects/noir-protocol-circuits/crates/rollup-block-root num_runs: 1 timeout: 60 - compilation-timeout: 110 + compilation-timeout: 120 execution-timeout: 40 compilation-memory-limit: 8000 execution-memory-limit: 1500 diff --git a/.gitignore b/.gitignore index 1d76c98a1ac..334901860d9 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ codegen **/cspell.json !./cspell.json + +mutants.out +mutants.out.old diff --git a/Cargo.toml b/Cargo.toml index ca954e5846f..9c5bf1351d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ resolver = "2" version = "1.0.0-beta.3" # x-release-please-end authors = ["The Noir Team "] -edition = "2021" +edition = "2024" rust-version = "1.85.0" license = "MIT OR Apache-2.0" repository = "https://github.com/noir-lang/noir/" diff --git a/EXTERNAL_NOIR_LIBRARIES.yml b/EXTERNAL_NOIR_LIBRARIES.yml index 0481c539805..dc8af205bf3 100644 --- a/EXTERNAL_NOIR_LIBRARIES.yml +++ b/EXTERNAL_NOIR_LIBRARIES.yml @@ -1,4 +1,4 @@ -define: &AZ_COMMIT a90f08e245add379fa0257c81f8e2819beb190cb +define: &AZ_COMMIT cca90e5e655ed9a2d2bb969f034e42ac15f87439 libraries: noir_check_shuffle: repo: noir-lang/noir_check_shuffle @@ -29,7 +29,7 @@ libraries: timeout: 250 noir_base64: repo: noir-lang/noir_base64 - timeout: 3 + timeout: 5 noir_string_search: repo: noir-lang/noir_string_search timeout: 2 diff --git a/acvm-repo/acir/benches/serialization.rs b/acvm-repo/acir/benches/serialization.rs index dd6a5c8b1cf..2725b3e1dd0 100644 --- a/acvm-repo/acir/benches/serialization.rs +++ b/acvm-repo/acir/benches/serialization.rs @@ -1,10 +1,10 @@ -use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; +use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main}; use std::{collections::BTreeSet, time::Duration}; use acir::{ + FieldElement, circuit::{Circuit, ExpressionWidth, Opcode, Program, PublicInputs}, native_types::{Expression, Witness}, - FieldElement, }; use pprof::criterion::{Output, PProfProfiler}; diff --git a/acvm-repo/acir/src/circuit/mod.rs b/acvm-repo/acir/src/circuit/mod.rs index d0f12b1168e..68c3c832b5c 100644 --- a/acvm-repo/acir/src/circuit/mod.rs +++ b/acvm-repo/acir/src/circuit/mod.rs @@ -11,7 +11,7 @@ use std::{io::prelude::*, num::ParseIntError, str::FromStr}; use base64::Engine; use flate2::Compression; -use serde::{de::Error as DeserializationError, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeserializationError}; use std::collections::BTreeSet; @@ -375,8 +375,8 @@ mod tests { use std::collections::BTreeSet; use super::{ - opcodes::{BlackBoxFuncCall, FunctionInput}, Circuit, Compression, Opcode, PublicInputs, + opcodes::{BlackBoxFuncCall, FunctionInput}, }; use crate::{ circuit::{ExpressionWidth, Program}, diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs index bb5b50c0daf..e49ab60f9e0 100644 --- a/acvm-repo/acir/src/lib.rs +++ b/acvm-repo/acir/src/lib.rs @@ -41,10 +41,10 @@ mod reflection { use crate::{ circuit::{ - brillig::{BrilligInputs, BrilligOutputs}, - opcodes::{BlackBoxFuncCall, BlockType, ConstantOrWitnessEnum, FunctionInput}, AssertionPayload, Circuit, ExpressionOrMemory, ExpressionWidth, Opcode, OpcodeLocation, Program, + brillig::{BrilligInputs, BrilligOutputs}, + opcodes::{BlackBoxFuncCall, BlockType, ConstantOrWitnessEnum, FunctionInput}, }, native_types::{Witness, WitnessMap, WitnessStack}, }; diff --git a/acvm-repo/acir/src/native_types/expression/ordering.rs b/acvm-repo/acir/src/native_types/expression/ordering.rs index f1d217b3bd9..968dc310bc1 100644 --- a/acvm-repo/acir/src/native_types/expression/ordering.rs +++ b/acvm-repo/acir/src/native_types/expression/ordering.rs @@ -85,11 +85,7 @@ impl Expression { fn cmp_max(m1: Option, m2: Option) -> Ordering { if let Some(m1) = m1 { - if let Some(m2) = m2 { - m1.cmp(&m2) - } else { - Ordering::Greater - } + if let Some(m2) = m2 { m1.cmp(&m2) } else { Ordering::Greater } } else if m2.is_some() { Ordering::Less } else { diff --git a/acvm-repo/acir/src/native_types/witness_map.rs b/acvm-repo/acir/src/native_types/witness_map.rs index e508fe5b186..77745c714a3 100644 --- a/acvm-repo/acir/src/native_types/witness_map.rs +++ b/acvm-repo/acir/src/native_types/witness_map.rs @@ -1,12 +1,12 @@ use std::{ - collections::{btree_map, BTreeMap}, + collections::{BTreeMap, btree_map}, io::Read, ops::Index, }; +use flate2::Compression; use flate2::bufread::GzDecoder; use flate2::bufread::GzEncoder; -use flate2::Compression; use serde::{Deserialize, Serialize}; use thiserror::Error; diff --git a/acvm-repo/acir/src/native_types/witness_stack.rs b/acvm-repo/acir/src/native_types/witness_stack.rs index 8a4fffa1577..6338ad630d6 100644 --- a/acvm-repo/acir/src/native_types/witness_stack.rs +++ b/acvm-repo/acir/src/native_types/witness_stack.rs @@ -1,8 +1,8 @@ use std::io::Read; +use flate2::Compression; use flate2::bufread::GzDecoder; use flate2::bufread::GzEncoder; -use flate2::Compression; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -12,6 +12,9 @@ use super::WitnessMap; enum SerializationError { #[error(transparent)] Deflate(#[from] std::io::Error), + + #[error(transparent)] + BincodeError(#[from] bincode::Error), } #[derive(Debug, Error)] @@ -57,11 +60,11 @@ impl From> for WitnessStack { } } -impl TryFrom> for Vec { +impl TryFrom<&WitnessStack> for Vec { type Error = WitnessStackError; - fn try_from(val: WitnessStack) -> Result { - let buf = bincode::serialize(&val).unwrap(); + fn try_from(val: &WitnessStack) -> Result { + let buf = bincode::serialize(val).map_err(|e| WitnessStackError(e.into()))?; let mut deflater = GzEncoder::new(buf.as_slice(), Compression::best()); let mut buf_c = Vec::new(); deflater.read_to_end(&mut buf_c).map_err(|err| WitnessStackError(err.into()))?; @@ -69,6 +72,14 @@ impl TryFrom> for Vec { } } +impl TryFrom> for Vec { + type Error = WitnessStackError; + + fn try_from(val: WitnessStack) -> Result { + Self::try_from(&val) + } +} + impl Deserialize<'a>> TryFrom<&[u8]> for WitnessStack { type Error = WitnessStackError; @@ -76,7 +87,8 @@ impl Deserialize<'a>> TryFrom<&[u8]> for WitnessStack { let mut deflater = GzDecoder::new(bytes); let mut buf_d = Vec::new(); deflater.read_to_end(&mut buf_d).map_err(|err| WitnessStackError(err.into()))?; - let witness_stack = bincode::deserialize(&buf_d).unwrap(); + let witness_stack = + bincode::deserialize(&buf_d).map_err(|e| WitnessStackError(e.into()))?; Ok(witness_stack) } } diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index 305d94abcee..4ff571106a1 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -13,9 +13,9 @@ use std::collections::BTreeSet; use acir::{ circuit::{ + Circuit, Opcode, Program, PublicInputs, brillig::{BrilligBytecode, BrilligFunctionId, BrilligInputs, BrilligOutputs}, opcodes::{AcirFunctionId, BlackBoxFuncCall, BlockId, FunctionInput, MemOp}, - Circuit, Opcode, Program, PublicInputs, }, native_types::{Expression, Witness}, }; diff --git a/acvm-repo/acir_field/benches/field_element.rs b/acvm-repo/acir_field/benches/field_element.rs index 6666e6dd9a1..8560c10cd04 100644 --- a/acvm-repo/acir_field/benches/field_element.rs +++ b/acvm-repo/acir_field/benches/field_element.rs @@ -1,5 +1,5 @@ use acir_field::{AcirField, FieldElement}; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use std::hint::black_box; fn criterion_benchmark(c: &mut Criterion) { diff --git a/acvm-repo/acir_field/src/field_element.rs b/acvm-repo/acir_field/src/field_element.rs index a11b1d26bbf..fdac33836ad 100644 --- a/acvm-repo/acir_field/src/field_element.rs +++ b/acvm-repo/acir_field/src/field_element.rs @@ -112,11 +112,7 @@ impl From for FieldElement { impl From for FieldElement { fn from(boolean: bool) -> FieldElement { - if boolean { - FieldElement::one() - } else { - FieldElement::zero() - } + if boolean { FieldElement::one() } else { FieldElement::zero() } } } @@ -183,11 +179,7 @@ impl AcirField for FieldElement { /// For example, a max bit size of 254 would give a max byte size of 32. fn max_num_bytes() -> u32 { let num_bytes = Self::max_num_bits() / 8; - if Self::max_num_bits() % 8 == 0 { - num_bytes - } else { - num_bytes + 1 - } + if Self::max_num_bits() % 8 == 0 { num_bytes } else { num_bytes + 1 } } fn modulus() -> BigUint { diff --git a/acvm-repo/acvm/src/compiler/mod.rs b/acvm-repo/acvm/src/compiler/mod.rs index ee84f7bf60b..ee503e7e0d0 100644 --- a/acvm-repo/acvm/src/compiler/mod.rs +++ b/acvm-repo/acvm/src/compiler/mod.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use acir::{ - circuit::{AssertionPayload, Circuit, ExpressionWidth, OpcodeLocation}, AcirField, + circuit::{AssertionPayload, Circuit, ExpressionWidth, OpcodeLocation}, }; // The various passes that we can use over ACIR @@ -14,7 +14,7 @@ pub use optimizers::optimize; use optimizers::optimize_internal; pub use simulator::CircuitSimulator; use transformers::transform_internal; -pub use transformers::{transform, MIN_EXPRESSION_WIDTH}; +pub use transformers::{MIN_EXPRESSION_WIDTH, transform}; /// This module moves and decomposes acir opcodes. The transformation map allows consumers of this module to map /// metadata they had about the opcodes to the new opcode structure generated after the transformation. diff --git a/acvm-repo/acvm/src/compiler/optimizers/general.rs b/acvm-repo/acvm/src/compiler/optimizers/general.rs index 39a01a38cac..0802f33185c 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/general.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/general.rs @@ -1,6 +1,6 @@ use acir::{ - native_types::{Expression, Witness}, AcirField, + native_types::{Expression, Witness}, }; use indexmap::IndexMap; diff --git a/acvm-repo/acvm/src/compiler/optimizers/merge_expressions.rs b/acvm-repo/acvm/src/compiler/optimizers/merge_expressions.rs index e95c6207c3c..2590c5f208a 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/merge_expressions.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/merge_expressions.rs @@ -1,13 +1,13 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; use acir::{ + AcirField, circuit::{ + Circuit, Opcode, brillig::{BrilligInputs, BrilligOutputs}, opcodes::BlockId, - Circuit, Opcode, }, native_types::{Expression, Witness}, - AcirField, }; use crate::compiler::CircuitSimulator; @@ -258,16 +258,16 @@ impl MergeExpressionsOptimizer { #[cfg(test)] mod tests { - use crate::compiler::{optimizers::MergeExpressionsOptimizer, CircuitSimulator}; + use crate::compiler::{CircuitSimulator, optimizers::MergeExpressionsOptimizer}; use acir::{ + FieldElement, acir_field::AcirField, circuit::{ + Circuit, ExpressionWidth, Opcode, PublicInputs, brillig::{BrilligFunctionId, BrilligOutputs}, opcodes::{BlackBoxFuncCall, FunctionInput}, - Circuit, ExpressionWidth, Opcode, PublicInputs, }, native_types::{Expression, Witness}, - FieldElement, }; use std::collections::BTreeSet; diff --git a/acvm-repo/acvm/src/compiler/optimizers/mod.rs b/acvm-repo/acvm/src/compiler/optimizers/mod.rs index 3531825c709..3e085e4ba9b 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/mod.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/mod.rs @@ -1,6 +1,6 @@ use acir::{ - circuit::{Circuit, Opcode}, AcirField, + circuit::{Circuit, Opcode}, }; // mod constant_backpropagation; @@ -17,7 +17,7 @@ use tracing::info; // use self::constant_backpropagation::ConstantBackpropagationOptimizer; use self::unused_memory::UnusedMemoryOptimizer; -use super::{transform_assert_messages, AcirTransformationMap}; +use super::{AcirTransformationMap, transform_assert_messages}; /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] independent optimizations to a [`Circuit`]. pub fn optimize(acir: Circuit) -> (Circuit, AcirTransformationMap) { diff --git a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs index f9c715a277f..67dce75411e 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs @@ -1,10 +1,10 @@ use acir::{ + AcirField, circuit::{ - opcodes::{BlackBoxFuncCall, ConstantOrWitnessEnum}, Circuit, Opcode, + opcodes::{BlackBoxFuncCall, ConstantOrWitnessEnum}, }, native_types::Witness, - AcirField, }; use std::collections::{BTreeMap, HashSet}; @@ -163,12 +163,12 @@ mod tests { use crate::compiler::optimizers::redundant_range::RangeOptimizer; use acir::{ + FieldElement, circuit::{ - opcodes::{BlackBoxFuncCall, FunctionInput}, Circuit, ExpressionWidth, Opcode, PublicInputs, + opcodes::{BlackBoxFuncCall, FunctionInput}, }, native_types::{Expression, Witness}, - FieldElement, }; fn test_circuit(ranges: Vec<(Witness, u32)>) -> Circuit { diff --git a/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs b/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs index 1325a3b03cd..8b7e52d66f2 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs @@ -1,4 +1,4 @@ -use acir::circuit::{brillig::BrilligInputs, opcodes::BlockId, Circuit, Opcode}; +use acir::circuit::{Circuit, Opcode, brillig::BrilligInputs, opcodes::BlockId}; use std::collections::HashSet; /// `UnusedMemoryOptimizer` will remove initializations of memory blocks which are unused. diff --git a/acvm-repo/acvm/src/compiler/simulator.rs b/acvm-repo/acvm/src/compiler/simulator.rs index 893195f342a..96134926f5e 100644 --- a/acvm-repo/acvm/src/compiler/simulator.rs +++ b/acvm-repo/acvm/src/compiler/simulator.rs @@ -1,11 +1,11 @@ use acir::{ + AcirField, circuit::{ + Circuit, Opcode, brillig::{BrilligInputs, BrilligOutputs}, opcodes::{BlockId, FunctionInput}, - Circuit, Opcode, }, native_types::{Expression, Witness}, - AcirField, }; use std::collections::{BTreeSet, HashMap, HashSet}; @@ -215,10 +215,10 @@ mod tests { use crate::compiler::CircuitSimulator; use acir::{ + FieldElement, acir_field::AcirField, circuit::{Circuit, ExpressionWidth, Opcode, PublicInputs}, native_types::{Expression, Witness}, - FieldElement, }; fn test_circuit( diff --git a/acvm-repo/acvm/src/compiler/transformers/csat.rs b/acvm-repo/acvm/src/compiler/transformers/csat.rs index bdd6998835a..8f890e4ca86 100644 --- a/acvm-repo/acvm/src/compiler/transformers/csat.rs +++ b/acvm-repo/acvm/src/compiler/transformers/csat.rs @@ -1,8 +1,8 @@ use std::{cmp::Ordering, collections::HashSet}; use acir::{ - native_types::{Expression, Witness}, AcirField, + native_types::{Expression, Witness}, }; use indexmap::IndexMap; @@ -201,7 +201,7 @@ impl CSatTransformer { // Now we have used up 2 spaces in our assert-zero opcode. The width now dictates, how many more we can add let mut remaining_space = self.width - 2 - 1; // We minus 1 because we need an extra space to contain the intermediate variable - // Keep adding terms until we have no more left, or we reach the width + // Keep adding terms until we have no more left, or we reach the width let mut remaining_linear_terms = Vec::with_capacity(opcode.linear_combinations.len()); while remaining_space > 0 { diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs index 77a5d2da34e..fe9404b075c 100644 --- a/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -1,12 +1,11 @@ use acir::{ + AcirField, circuit::{ - self, + self, Circuit, ExpressionWidth, Opcode, brillig::{BrilligInputs, BrilligOutputs}, opcodes::{BlackBoxFuncCall, FunctionInput, MemOp}, - Circuit, ExpressionWidth, Opcode, }, native_types::{Expression, Witness}, - AcirField, }; use indexmap::IndexMap; @@ -17,8 +16,9 @@ pub use csat::MIN_EXPRESSION_WIDTH; use tracing::info; use super::{ + AcirTransformationMap, optimizers::{MergeExpressionsOptimizer, RangeOptimizer}, - transform_assert_messages, AcirTransformationMap, + transform_assert_messages, }; /// We need multiple passes to stabilize the output. diff --git a/acvm-repo/acvm/src/pwg/arithmetic.rs b/acvm-repo/acvm/src/pwg/arithmetic.rs index 5eeabd8a833..a2921bcbc9b 100644 --- a/acvm-repo/acvm/src/pwg/arithmetic.rs +++ b/acvm-repo/acvm/src/pwg/arithmetic.rs @@ -1,9 +1,9 @@ use acir::{ - native_types::{Expression, Witness, WitnessMap}, AcirField, + native_types::{Expression, Witness, WitnessMap}, }; -use super::{insert_value, ErrorLocation, OpcodeNotSolvable, OpcodeResolutionError}; +use super::{ErrorLocation, OpcodeNotSolvable, OpcodeResolutionError, insert_value}; /// An Expression solver will take a Circuit's assert-zero opcodes with witness assignments /// and create the other witness variables @@ -254,7 +254,52 @@ mod tests { use acir::FieldElement; #[test] - fn expression_solver_smoke_test() { + fn solves_simple_assignment() { + let a = Witness(0); + + // a - 1 == 0; + let opcode_a = Expression { + mul_terms: vec![], + linear_combinations: vec![(FieldElement::one(), a)], + q_c: -FieldElement::one(), + }; + + let mut values = WitnessMap::new(); + assert_eq!(ExpressionSolver::solve(&mut values, &opcode_a), Ok(())); + + assert_eq!(values.get(&a).unwrap(), &FieldElement::from(1_i128)); + } + + #[test] + fn solves_unknown_in_mul_term() { + let a = Witness(0); + let b = Witness(1); + let c = Witness(2); + let d = Witness(3); + + // a * b - b - c - d == 0; + let opcode_a = Expression { + mul_terms: vec![(FieldElement::one(), a, b)], + linear_combinations: vec![ + (-FieldElement::one(), b), + (-FieldElement::one(), c), + (-FieldElement::one(), d), + ], + q_c: FieldElement::zero(), + }; + + let mut values = WitnessMap::new(); + values.insert(b, FieldElement::from(2_i128)); + values.insert(c, FieldElement::from(1_i128)); + values.insert(d, FieldElement::from(1_i128)); + + assert_eq!(ExpressionSolver::solve(&mut values, &opcode_a), Ok(())); + + assert_eq!(values.get(&a).unwrap(), &FieldElement::from(2_i128)); + } + + #[test] + fn solves_unknown_in_linear_term() { let a = Witness(0); let b = Witness(1); let c = Witness(2); diff --git a/acvm-repo/acvm/src/pwg/blackbox/aes128.rs b/acvm-repo/acvm/src/pwg/blackbox/aes128.rs index e3c8dc78aa6..e241a39f5af 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/aes128.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/aes128.rs @@ -1,11 +1,11 @@ use acir::{ + AcirField, circuit::opcodes::FunctionInput, native_types::{Witness, WitnessMap}, - AcirField, }; use acvm_blackbox_solver::aes128_encrypt; -use crate::{pwg::insert_value, OpcodeResolutionError}; +use crate::{OpcodeResolutionError, pwg::insert_value}; use super::utils::{to_u8_array, to_u8_vec}; diff --git a/acvm-repo/acvm/src/pwg/blackbox/bigint.rs b/acvm-repo/acvm/src/pwg/blackbox/bigint.rs index eb5a6f81e7d..1c5a436fa11 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/bigint.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/bigint.rs @@ -1,8 +1,8 @@ use crate::pwg::input_to_value; use acir::{ + AcirField, BlackBoxFunc, circuit::opcodes::FunctionInput, native_types::{Witness, WitnessMap}, - AcirField, BlackBoxFunc, }; use acvm_blackbox_solver::BigIntSolver; diff --git a/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs b/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs index 9e511571275..2c728e77304 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs @@ -1,11 +1,11 @@ use acir::{ + AcirField, circuit::opcodes::FunctionInput, native_types::{Witness, WitnessMap}, - AcirField, }; use acvm_blackbox_solver::BlackBoxFunctionSolver; -use crate::pwg::{input_to_value, insert_value, OpcodeResolutionError}; +use crate::pwg::{OpcodeResolutionError, input_to_value, insert_value}; pub(super) fn multi_scalar_mul( backend: &impl BlackBoxFunctionSolver, diff --git a/acvm-repo/acvm/src/pwg/blackbox/hash.rs b/acvm-repo/acvm/src/pwg/blackbox/hash.rs index 438b3559e8e..a4af9de55cf 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/hash.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/hash.rs @@ -1,12 +1,12 @@ use acir::{ + AcirField, circuit::opcodes::FunctionInput, native_types::{Witness, WitnessMap}, - AcirField, }; -use acvm_blackbox_solver::{sha256_compression, BlackBoxFunctionSolver, BlackBoxResolutionError}; +use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError, sha256_compression}; -use crate::pwg::{input_to_value, insert_value}; use crate::OpcodeResolutionError; +use crate::pwg::{input_to_value, insert_value}; /// Attempts to solve a 256 bit hash function opcode. /// If successful, `initial_witness` will be mutated to contain the new witness assignment. @@ -136,11 +136,10 @@ pub(crate) fn solve_poseidon2_permutation_opcode( } // Read witness assignments - let mut state = Vec::new(); - for input in inputs.iter() { - let witness_assignment = input_to_value(initial_witness, *input, false)?; - state.push(witness_assignment); - } + let state: Vec = inputs + .iter() + .map(|input| input_to_value(initial_witness, *input, false)) + .collect::>()?; let state = backend.poseidon2_permutation(&state, len)?; diff --git a/acvm-repo/acvm/src/pwg/blackbox/logic.rs b/acvm-repo/acvm/src/pwg/blackbox/logic.rs index 3fa72d9b215..587add11b81 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/logic.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/logic.rs @@ -1,9 +1,9 @@ -use crate::pwg::{input_to_value, insert_value}; use crate::OpcodeResolutionError; +use crate::pwg::{input_to_value, insert_value}; use acir::{ + AcirField, circuit::opcodes::FunctionInput, native_types::{Witness, WitnessMap}, - AcirField, }; use acvm_blackbox_solver::{bit_and, bit_xor}; diff --git a/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 2f10e333c24..ad064fefd7b 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -1,7 +1,7 @@ use acir::{ + AcirField, circuit::opcodes::{BlackBoxFuncCall, ConstantOrWitnessEnum, FunctionInput}, native_types::{Witness, WitnessMap}, - AcirField, }; use acvm_blackbox_solver::{blake2s, blake3, keccakf1600}; @@ -10,8 +10,8 @@ use self::{ hash::solve_poseidon2_permutation_opcode, }; -use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; -use crate::{pwg::input_to_value, BlackBoxFunctionSolver}; +use super::{OpcodeNotSolvable, OpcodeResolutionError, insert_value}; +use crate::{BlackBoxFunctionSolver, pwg::input_to_value}; mod aes128; pub(crate) mod bigint; @@ -37,12 +37,8 @@ fn first_missing_assignment( inputs: &[FunctionInput], ) -> Option { inputs.iter().find_map(|input| { - if let ConstantOrWitnessEnum::Witness(ref witness) = input.input_ref() { - if witness_assignments.contains_key(witness) { - None - } else { - Some(*witness) - } + if let ConstantOrWitnessEnum::Witness(witness) = input.input_ref() { + if witness_assignments.contains_key(witness) { None } else { Some(*witness) } } else { None } diff --git a/acvm-repo/acvm/src/pwg/blackbox/range.rs b/acvm-repo/acvm/src/pwg/blackbox/range.rs index d7083e4b9c0..039a04b9063 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/range.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/range.rs @@ -1,8 +1,8 @@ use crate::{ - pwg::{input_to_value, ErrorLocation}, OpcodeResolutionError, + pwg::{ErrorLocation, input_to_value}, }; -use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap, AcirField}; +use acir::{AcirField, circuit::opcodes::FunctionInput, native_types::WitnessMap}; pub(crate) fn solve_range_opcode( initial_witness: &WitnessMap, @@ -21,3 +21,36 @@ pub(crate) fn solve_range_opcode( } Ok(()) } + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use acir::{ + FieldElement, + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + }; + + use crate::pwg::blackbox::solve_range_opcode; + + #[test] + fn rejects_too_large_inputs() { + let witness_map = + WitnessMap::from(BTreeMap::from([(Witness(0), FieldElement::from(256u32))])); + let input: FunctionInput = FunctionInput::witness(Witness(0), 8); + assert!(solve_range_opcode(&witness_map, &input, false).is_err()); + } + + #[test] + fn accepts_valid_inputs() { + let values: [u32; 4] = [0, 1, 8, 255]; + + for value in values { + let witness_map = + WitnessMap::from(BTreeMap::from([(Witness(0), FieldElement::from(value))])); + let input: FunctionInput = FunctionInput::witness(Witness(0), 8); + assert!(solve_range_opcode(&witness_map, &input, false).is_ok()); + } + } +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs b/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs index db92d27b871..4b53316e88f 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs @@ -1,16 +1,16 @@ use acir::{ + AcirField, circuit::opcodes::FunctionInput, native_types::{Witness, WitnessMap}, - AcirField, }; use acvm_blackbox_solver::{ecdsa_secp256k1_verify, ecdsa_secp256r1_verify}; use crate::{ + OpcodeResolutionError, pwg::{ blackbox::utils::{to_u8_array, to_u8_vec}, insert_value, }, - OpcodeResolutionError, }; pub(crate) fn secp256k1_prehashed( diff --git a/acvm-repo/acvm/src/pwg/blackbox/utils.rs b/acvm-repo/acvm/src/pwg/blackbox/utils.rs index b966cb0cc5d..6c9c5a1025a 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/utils.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/utils.rs @@ -1,6 +1,6 @@ -use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap, AcirField}; +use acir::{AcirField, circuit::opcodes::FunctionInput, native_types::WitnessMap}; -use crate::pwg::{input_to_value, OpcodeResolutionError}; +use crate::pwg::{OpcodeResolutionError, input_to_value}; pub(crate) fn to_u8_array( initial_witness: &WitnessMap, diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 9625685c6d1..136f358b9bb 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -1,20 +1,20 @@ use std::collections::HashMap; use acir::{ + AcirField, brillig::{ForeignCallParam, ForeignCallResult, Opcode as BrilligOpcode}, circuit::{ + ErrorSelector, OpcodeLocation, RawAssertionPayload, ResolvedAssertionPayload, brillig::{BrilligFunctionId, BrilligInputs, BrilligOutputs}, opcodes::BlockId, - ErrorSelector, OpcodeLocation, RawAssertionPayload, ResolvedAssertionPayload, }, native_types::WitnessMap, - AcirField, }; use acvm_blackbox_solver::BlackBoxFunctionSolver; -use brillig_vm::{BrilligProfilingSamples, FailureReason, MemoryValue, VMStatus, VM}; +use brillig_vm::{BrilligProfilingSamples, FailureReason, MemoryValue, VM, VMStatus}; use serde::{Deserialize, Serialize}; -use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; +use crate::{OpcodeResolutionError, pwg::OpcodeNotSolvable}; use super::{get_value, insert_value, memory_op::MemoryOpSolver}; diff --git a/acvm-repo/acvm/src/pwg/memory_op.rs b/acvm-repo/acvm/src/pwg/memory_op.rs index 2a83bf2531c..aef18d3957e 100644 --- a/acvm-repo/acvm/src/pwg/memory_op.rs +++ b/acvm-repo/acvm/src/pwg/memory_op.rs @@ -1,15 +1,15 @@ use std::collections::HashMap; use acir::{ + AcirField, circuit::opcodes::MemOp, native_types::{Expression, Witness, WitnessMap}, - AcirField, }; +use super::{ErrorLocation, OpcodeResolutionError}; use super::{ arithmetic::ExpressionSolver, get_value, insert_value, is_predicate_false, witness_to_value, }; -use super::{ErrorLocation, OpcodeResolutionError}; type MemoryIndex = u32; @@ -140,9 +140,9 @@ mod tests { use std::collections::BTreeMap; use acir::{ + AcirField, FieldElement, circuit::opcodes::MemOp, native_types::{Expression, Witness, WitnessMap}, - AcirField, FieldElement, }; use super::MemoryOpSolver; diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index 8a6ca597b2f..f5d56df17c1 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -3,17 +3,17 @@ use std::collections::HashMap; use acir::{ + AcirField, BlackBoxFunc, brillig::ForeignCallResult, circuit::{ + AssertionPayload, ErrorSelector, ExpressionOrMemory, Opcode, OpcodeLocation, + RawAssertionPayload, ResolvedAssertionPayload, brillig::{BrilligBytecode, BrilligFunctionId}, opcodes::{ AcirFunctionId, BlockId, ConstantOrWitnessEnum, FunctionInput, InvalidInputBitSize, }, - AssertionPayload, ErrorSelector, ExpressionOrMemory, Opcode, OpcodeLocation, - RawAssertionPayload, ResolvedAssertionPayload, }, native_types::{Expression, Witness, WitnessMap}, - AcirField, BlackBoxFunc, }; use acvm_blackbox_solver::BlackBoxResolutionError; @@ -747,11 +747,7 @@ pub fn insert_value( // The function is used during partial witness generation to report unsolved witness fn any_witness_from_expression(expr: &Expression) -> Option { if expr.linear_combinations.is_empty() { - if expr.mul_terms.is_empty() { - None - } else { - Some(expr.mul_terms[0].1) - } + if expr.mul_terms.is_empty() { None } else { Some(expr.mul_terms[0].1) } } else { Some(expr.linear_combinations[0].1) } diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 2fd61050377..ce75a7d2001 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -3,20 +3,20 @@ use std::sync::Arc; use acir::brillig::{BitSize, HeapVector, IntegerBitSize}; use acir::{ + AcirField, FieldElement, acir_field::GenericFieldElement, brillig::{BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray}, circuit::{ + Opcode, OpcodeLocation, brillig::{BrilligBytecode, BrilligFunctionId, BrilligInputs, BrilligOutputs}, opcodes::{BlackBoxFuncCall, BlockId, BlockType, FunctionInput, MemOp}, - Opcode, OpcodeLocation, }, native_types::{Expression, Witness, WitnessMap}, - AcirField, FieldElement, }; -use acvm::pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolutionError, ACVM}; +use acvm::pwg::{ACVM, ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolutionError}; use acvm_blackbox_solver::{BigIntSolver, StubbedBlackBoxSolver}; -use bn254_blackbox_solver::{field_from_hex, Bn254BlackBoxSolver, POSEIDON2_CONFIG}; +use bn254_blackbox_solver::{Bn254BlackBoxSolver, POSEIDON2_CONFIG, field_from_hex}; use brillig_vm::brillig::HeapValueType; use num_bigint::BigUint; diff --git a/acvm-repo/acvm_js/src/black_box_solvers.rs b/acvm-repo/acvm_js/src/black_box_solvers.rs index 0e35851ee78..02c026cd26f 100644 --- a/acvm-repo/acvm_js/src/black_box_solvers.rs +++ b/acvm-repo/acvm_js/src/black_box_solvers.rs @@ -2,7 +2,7 @@ use js_sys::JsString; use wasm_bindgen::prelude::*; use crate::js_witness_map::{field_element_to_js_string, js_value_to_field_element}; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; /// Performs a bitwise AND operation between `lhs` and `rhs` #[wasm_bindgen] diff --git a/acvm-repo/acvm_js/src/execute.rs b/acvm-repo/acvm_js/src/execute.rs index e4d52063977..3efa6900f6e 100644 --- a/acvm-repo/acvm_js/src/execute.rs +++ b/acvm-repo/acvm_js/src/execute.rs @@ -1,22 +1,22 @@ use std::{future::Future, pin::Pin}; -use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::circuit::ResolvedAssertionPayload; +use acvm::acir::circuit::brillig::BrilligBytecode; +use acvm::{BlackBoxFunctionSolver, FieldElement}; use acvm::{ acir::circuit::{Circuit, Program}, acir::native_types::{WitnessMap, WitnessStack}, - pwg::{ACVMStatus, ErrorLocation, OpcodeResolutionError, ACVM}, + pwg::{ACVM, ACVMStatus, ErrorLocation, OpcodeResolutionError}, }; -use acvm::{BlackBoxFunctionSolver, FieldElement}; use bn254_blackbox_solver::Bn254BlackBoxSolver; use js_sys::Error; use wasm_bindgen::prelude::wasm_bindgen; use crate::{ - foreign_call::{resolve_brillig, ForeignCallHandler}, - public_witness::extract_indices, JsExecutionError, JsSolvedAndReturnWitness, JsWitnessMap, JsWitnessStack, + foreign_call::{ForeignCallHandler, resolve_brillig}, + public_witness::extract_indices, }; /// Executes an ACIR circuit to generate the solved witness from the initial witness. diff --git a/acvm-repo/acvm_js/src/foreign_call/inputs.rs b/acvm-repo/acvm_js/src/foreign_call/inputs.rs index dd12bc639ec..eee36a0f01a 100644 --- a/acvm-repo/acvm_js/src/foreign_call/inputs.rs +++ b/acvm-repo/acvm_js/src/foreign_call/inputs.rs @@ -1,4 +1,4 @@ -use acvm::{brillig_vm::brillig::ForeignCallParam, FieldElement}; +use acvm::{FieldElement, brillig_vm::brillig::ForeignCallParam}; use crate::js_witness_map::field_element_to_js_string; diff --git a/acvm-repo/acvm_js/src/foreign_call/mod.rs b/acvm-repo/acvm_js/src/foreign_call/mod.rs index 4884c1173dc..8b34b699a85 100644 --- a/acvm-repo/acvm_js/src/foreign_call/mod.rs +++ b/acvm-repo/acvm_js/src/foreign_call/mod.rs @@ -1,7 +1,7 @@ -use acvm::{brillig_vm::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, FieldElement}; +use acvm::{FieldElement, brillig_vm::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo}; use js_sys::{Error, JsString}; -use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; +use wasm_bindgen::{JsValue, prelude::wasm_bindgen}; mod inputs; mod outputs; diff --git a/acvm-repo/acvm_js/src/foreign_call/outputs.rs b/acvm-repo/acvm_js/src/foreign_call/outputs.rs index 2b3f44fe98d..75b9c3aa311 100644 --- a/acvm-repo/acvm_js/src/foreign_call/outputs.rs +++ b/acvm-repo/acvm_js/src/foreign_call/outputs.rs @@ -1,6 +1,6 @@ use acvm::{ - brillig_vm::brillig::{ForeignCallParam, ForeignCallResult}, FieldElement, + brillig_vm::brillig::{ForeignCallParam, ForeignCallResult}, }; use wasm_bindgen::JsValue; diff --git a/acvm-repo/acvm_js/src/js_execution_error.rs b/acvm-repo/acvm_js/src/js_execution_error.rs index f6a00af7942..6aa7cf75678 100644 --- a/acvm-repo/acvm_js/src/js_execution_error.rs +++ b/acvm-repo/acvm_js/src/js_execution_error.rs @@ -1,10 +1,10 @@ use acvm::{ - acir::circuit::{brillig::BrilligFunctionId, OpcodeLocation, RawAssertionPayload}, FieldElement, + acir::circuit::{OpcodeLocation, RawAssertionPayload, brillig::BrilligFunctionId}, }; use gloo_utils::format::JsValueSerdeExt; use js_sys::{Array, Error, JsString, Reflect}; -use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; +use wasm_bindgen::prelude::{JsValue, wasm_bindgen}; #[wasm_bindgen(typescript_custom_section)] const EXECUTION_ERROR: &'static str = r#" diff --git a/acvm-repo/acvm_js/src/js_witness_map.rs b/acvm-repo/acvm_js/src/js_witness_map.rs index 0ca58549495..a09e8e1ade7 100644 --- a/acvm-repo/acvm_js/src/js_witness_map.rs +++ b/acvm-repo/acvm_js/src/js_witness_map.rs @@ -1,10 +1,10 @@ use acvm::{ - acir::native_types::{Witness, WitnessMap}, - acir::AcirField, FieldElement, + acir::AcirField, + acir::native_types::{Witness, WitnessMap}, }; use js_sys::{JsString, Map, Object}; -use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; +use wasm_bindgen::prelude::{JsValue, wasm_bindgen}; #[wasm_bindgen(typescript_custom_section)] const WITNESS_MAP: &'static str = r#" @@ -113,8 +113,8 @@ mod test { use std::collections::BTreeMap; use acvm::{ - acir::native_types::{Witness, WitnessMap}, AcirField, FieldElement, + acir::native_types::{Witness, WitnessMap}, }; use wasm_bindgen::JsValue; diff --git a/acvm-repo/acvm_js/src/js_witness_stack.rs b/acvm-repo/acvm_js/src/js_witness_stack.rs index d59ee508086..e1baa491727 100644 --- a/acvm-repo/acvm_js/src/js_witness_stack.rs +++ b/acvm-repo/acvm_js/src/js_witness_stack.rs @@ -1,6 +1,6 @@ -use acvm::{acir::native_types::WitnessStack, FieldElement}; +use acvm::{FieldElement, acir::native_types::WitnessStack}; use js_sys::{Array, Map, Object}; -use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; +use wasm_bindgen::prelude::{JsValue, wasm_bindgen}; use crate::JsWitnessMap; diff --git a/acvm-repo/acvm_js/src/logging.rs b/acvm-repo/acvm_js/src/logging.rs index 483c23ab624..f40e2fa1bd3 100644 --- a/acvm-repo/acvm_js/src/logging.rs +++ b/acvm-repo/acvm_js/src/logging.rs @@ -1,6 +1,6 @@ use js_sys::{Error, JsString}; -use tracing_subscriber::prelude::*; use tracing_subscriber::EnvFilter; +use tracing_subscriber::prelude::*; use tracing_web::MakeWebConsoleWriter; use wasm_bindgen::prelude::*; diff --git a/acvm-repo/acvm_js/src/public_witness.rs b/acvm-repo/acvm_js/src/public_witness.rs index a50cb640b63..2ca794ba3a5 100644 --- a/acvm-repo/acvm_js/src/public_witness.rs +++ b/acvm-repo/acvm_js/src/public_witness.rs @@ -1,9 +1,9 @@ use acvm::{ + FieldElement, acir::{ circuit::Program, native_types::{Witness, WitnessMap}, }, - FieldElement, }; use js_sys::JsString; use wasm_bindgen::prelude::wasm_bindgen; diff --git a/acvm-repo/blackbox_solver/src/bigint.rs b/acvm-repo/blackbox_solver/src/bigint.rs index 6b70d51d791..d3531007f09 100644 --- a/acvm-repo/blackbox_solver/src/bigint.rs +++ b/acvm-repo/blackbox_solver/src/bigint.rs @@ -220,8 +220,8 @@ impl BigIntSolverWithId { #[test] fn all_allowed_bigint_moduli_are_prime() { - use num_prime::nt_funcs::is_prime; use num_prime::Primality; + use num_prime::nt_funcs::is_prime; for modulus in BigIntSolver::allowed_bigint_moduli() { let modulus = BigUint::from_bytes_le(&modulus); diff --git a/acvm-repo/blackbox_solver/src/curve_specific_solver.rs b/acvm-repo/blackbox_solver/src/curve_specific_solver.rs index 37fe5d05363..af0104b54f0 100644 --- a/acvm-repo/blackbox_solver/src/curve_specific_solver.rs +++ b/acvm-repo/blackbox_solver/src/curve_specific_solver.rs @@ -25,8 +25,8 @@ pub trait BlackBoxFunctionSolver { ) -> Result<(F, F, F), BlackBoxResolutionError>; fn poseidon2_permutation( &self, - _inputs: &[F], - _len: u32, + inputs: &[F], + len: u32, ) -> Result, BlackBoxResolutionError>; } diff --git a/acvm-repo/blackbox_solver/src/ecdsa/secp256k1.rs b/acvm-repo/blackbox_solver/src/ecdsa/secp256k1.rs index 17c51353f7f..d090029b1cd 100644 --- a/acvm-repo/blackbox_solver/src/ecdsa/secp256k1.rs +++ b/acvm-repo/blackbox_solver/src/ecdsa/secp256k1.rs @@ -1,15 +1,15 @@ -use k256::elliptic_curve::sec1::FromEncodedPoint; use k256::elliptic_curve::PrimeField; +use k256::elliptic_curve::sec1::FromEncodedPoint; use blake2::digest::generic_array::GenericArray; -use k256::{ecdsa::Signature, Scalar}; use k256::{ + AffinePoint, EncodedPoint, ProjectivePoint, PublicKey, elliptic_curve::{ - sec1::{Coordinates, ToEncodedPoint}, IsHigh, + sec1::{Coordinates, ToEncodedPoint}, }, - AffinePoint, EncodedPoint, ProjectivePoint, PublicKey, }; +use k256::{Scalar, ecdsa::Signature}; pub(super) fn verify_signature( hashed_msg: &[u8], diff --git a/acvm-repo/blackbox_solver/src/ecdsa/secp256r1.rs b/acvm-repo/blackbox_solver/src/ecdsa/secp256r1.rs index 54559d7c774..7a162aa800a 100644 --- a/acvm-repo/blackbox_solver/src/ecdsa/secp256r1.rs +++ b/acvm-repo/blackbox_solver/src/ecdsa/secp256r1.rs @@ -1,15 +1,15 @@ -use p256::elliptic_curve::sec1::FromEncodedPoint; use p256::elliptic_curve::PrimeField; +use p256::elliptic_curve::sec1::FromEncodedPoint; use blake2::digest::generic_array::GenericArray; -use p256::{ecdsa::Signature, Scalar}; use p256::{ + AffinePoint, EncodedPoint, ProjectivePoint, PublicKey, elliptic_curve::{ - sec1::{Coordinates, ToEncodedPoint}, IsHigh, + sec1::{Coordinates, ToEncodedPoint}, }, - AffinePoint, EncodedPoint, ProjectivePoint, PublicKey, }; +use p256::{Scalar, ecdsa::Signature}; pub(super) fn verify_signature( hashed_msg: &[u8], diff --git a/acvm-repo/bn254_blackbox_solver/benches/criterion.rs b/acvm-repo/bn254_blackbox_solver/benches/criterion.rs index fc566b70a26..05211264beb 100644 --- a/acvm-repo/bn254_blackbox_solver/benches/criterion.rs +++ b/acvm-repo/bn254_blackbox_solver/benches/criterion.rs @@ -1,4 +1,4 @@ -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use std::{hint::black_box, time::Duration}; use acir::{AcirField, FieldElement}; diff --git a/acvm-repo/bn254_blackbox_solver/src/generator/hash_to_curve.rs b/acvm-repo/bn254_blackbox_solver/src/generator/hash_to_curve.rs index 3c284fa811c..028ca2e5d1c 100644 --- a/acvm-repo/bn254_blackbox_solver/src/generator/hash_to_curve.rs +++ b/acvm-repo/bn254_blackbox_solver/src/generator/hash_to_curve.rs @@ -62,11 +62,7 @@ pub(crate) fn hash_to_curve(seed: &[u8], attempt_count: u8) -> Affine { if let Some(point) = Affine::get_point_from_x_unchecked(x, false) { let parity_bit = hash_hi[0] > 127; let y_bit_set = point.y().unwrap().into_bigint().get_bit(0); - if (parity_bit && !y_bit_set) || (!parity_bit && y_bit_set) { - -point - } else { - point - } + if (parity_bit && !y_bit_set) || (!parity_bit && y_bit_set) { -point } else { point } } else { hash_to_curve(seed, attempt_count + 1) } diff --git a/acvm-repo/bn254_blackbox_solver/src/lib.rs b/acvm-repo/bn254_blackbox_solver/src/lib.rs index fc031faefa2..d0fece86d6f 100644 --- a/acvm-repo/bn254_blackbox_solver/src/lib.rs +++ b/acvm-repo/bn254_blackbox_solver/src/lib.rs @@ -11,8 +11,8 @@ mod poseidon2; pub use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul}; pub use generator::generators::derive_generators; pub use poseidon2::{ - field_from_hex, poseidon2_permutation, poseidon_hash, Poseidon2Config, Poseidon2Sponge, - POSEIDON2_CONFIG, + POSEIDON2_CONFIG, Poseidon2Config, Poseidon2Sponge, field_from_hex, poseidon_hash, + poseidon2_permutation, }; // Temporary hack, this ensure that we always use a bn254 field here diff --git a/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs b/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs index 8a501b7e8a2..d756f40a236 100644 --- a/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs +++ b/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs @@ -626,7 +626,7 @@ impl<'a> Poseidon2Sponge<'a> { mod test { use acir::AcirField; - use super::{field_from_hex, poseidon2_permutation, FieldElement}; + use super::{FieldElement, field_from_hex, poseidon2_permutation}; #[test] fn smoke_test() { diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index be9ba20ed49..eb496d0f826 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -1,4 +1,4 @@ -use crate::{opcodes::HeapVector, HeapArray, MemoryAddress}; +use crate::{HeapArray, MemoryAddress, opcodes::HeapVector}; use serde::{Deserialize, Serialize}; /// These opcodes provide an equivalent of ACIR blackbox functions. diff --git a/acvm-repo/brillig_vm/src/arithmetic.rs b/acvm-repo/brillig_vm/src/arithmetic.rs index c9417faaff3..24013d1fde7 100644 --- a/acvm-repo/brillig_vm/src/arithmetic.rs +++ b/acvm-repo/brillig_vm/src/arithmetic.rs @@ -1,7 +1,7 @@ use std::ops::{BitAnd, BitOr, BitXor, Shl, Shr}; -use acir::brillig::{BinaryFieldOp, BinaryIntOp, BitSize, IntegerBitSize}; use acir::AcirField; +use acir::brillig::{BinaryFieldOp, BinaryIntOp, BitSize, IntegerBitSize}; use num_bigint::BigUint; use num_traits::{CheckedDiv, WrappingAdd, WrappingMul, WrappingSub, Zero}; @@ -231,21 +231,11 @@ fn evaluate_binary_int_op_shifts + Zero + Shl + Shr { let rhs_usize: usize = rhs as usize; - #[allow(unused_qualifications)] - if rhs_usize >= 8 * std::mem::size_of::() { - T::zero() - } else { - lhs << rhs.into() - } + if rhs_usize >= 8 * size_of::() { T::zero() } else { lhs << rhs.into() } } BinaryIntOp::Shr => { let rhs_usize: usize = rhs as usize; - #[allow(unused_qualifications)] - if rhs_usize >= 8 * std::mem::size_of::() { - T::zero() - } else { - lhs >> rhs.into() - } + if rhs_usize >= 8 * size_of::() { T::zero() } else { lhs >> rhs.into() } } _ => unreachable!("Operator not handled by this function: {op:?}"), } diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index aa3d0de55f4..74ea3568a1a 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -1,14 +1,14 @@ use acir::brillig::{BlackBoxOp, HeapArray, HeapVector}; use acir::{AcirField, BlackBoxFunc}; use acvm_blackbox_solver::{ - aes128_encrypt, blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccakf1600, - sha256_compression, BigIntSolverWithId, BlackBoxFunctionSolver, BlackBoxResolutionError, + BigIntSolverWithId, BlackBoxFunctionSolver, BlackBoxResolutionError, aes128_encrypt, blake2s, + blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccakf1600, sha256_compression, }; use num_bigint::BigUint; use num_traits::Zero; -use crate::memory::MemoryValue; use crate::Memory; +use crate::memory::MemoryValue; fn read_heap_vector<'a, F: AcirField>( memory: &'a Memory, diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 157ed9638ca..935c296d5ae 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -10,19 +10,19 @@ //! [acir]: https://crates.io/crates/acir //! [acvm]: https://crates.io/crates/acvm +use acir::AcirField; use acir::brillig::{ BinaryFieldOp, BinaryIntOp, BitSize, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, HeapVector, IntegerBitSize, MemoryAddress, Opcode, ValueOrArray, }; -use acir::AcirField; use acvm_blackbox_solver::BlackBoxFunctionSolver; -use arithmetic::{evaluate_binary_field_op, evaluate_binary_int_op, BrilligArithmeticError}; -use black_box::{evaluate_black_box, BrilligBigIntSolver}; +use arithmetic::{BrilligArithmeticError, evaluate_binary_field_op, evaluate_binary_int_op}; +use black_box::{BrilligBigIntSolver, evaluate_black_box}; // Re-export `brillig`. pub use acir::brillig; use memory::MemoryTypeError; -pub use memory::{Memory, MemoryValue, MEMORY_ADDRESSING_BIT_SIZE}; +pub use memory::{MEMORY_ADDRESSING_BIT_SIZE, Memory, MemoryValue}; mod arithmetic; mod black_box; diff --git a/acvm-repo/brillig_vm/src/memory.rs b/acvm-repo/brillig_vm/src/memory.rs index 5c04858fea7..33a760b52f5 100644 --- a/acvm-repo/brillig_vm/src/memory.rs +++ b/acvm-repo/brillig_vm/src/memory.rs @@ -1,6 +1,6 @@ use acir::{ - brillig::{BitSize, IntegerBitSize, MemoryAddress}, AcirField, + brillig::{BitSize, IntegerBitSize, MemoryAddress}, }; pub const MEMORY_ADDRESSING_BIT_SIZE: IntegerBitSize = IntegerBitSize::U32; diff --git a/compiler/noirc_driver/src/abi_gen.rs b/compiler/noirc_driver/src/abi_gen.rs index 0ef5c5e3f7e..3bbe2181798 100644 --- a/compiler/noirc_driver/src/abi_gen.rs +++ b/compiler/noirc_driver/src/abi_gen.rs @@ -1,15 +1,15 @@ use std::collections::BTreeMap; -use acvm::acir::circuit::ErrorSelector; use acvm::AcirField; +use acvm::acir::circuit::ErrorSelector; use iter_extended::vecmap; use noirc_abi::{ Abi, AbiErrorType, AbiParameter, AbiReturnType, AbiType, AbiValue, AbiVisibility, Sign, }; use noirc_errors::Location; use noirc_evaluator::ErrorType; -use noirc_frontend::ast::{Signedness, Visibility}; use noirc_frontend::TypeBinding; +use noirc_frontend::ast::{Signedness, Visibility}; use noirc_frontend::{ hir::Context, hir_def::{ diff --git a/compiler/noirc_driver/src/contract.rs b/compiler/noirc_driver/src/contract.rs index 3aa93d70124..b4c5e9a3fca 100644 --- a/compiler/noirc_driver/src/contract.rs +++ b/compiler/noirc_driver/src/contract.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashMap}; -use acvm::{acir::circuit::Program, FieldElement}; +use acvm::{FieldElement, acir::circuit::Program}; use fm::FileId; use noirc_abi::{Abi, AbiType, AbiValue}; use noirc_errors::debug_info::DebugInfo; diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index c5d125c69dd..3712634d707 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -10,15 +10,15 @@ use clap::Args; use fm::{FileId, FileManager}; use iter_extended::vecmap; use noirc_abi::{AbiParameter, AbiType, AbiValue}; -use noirc_errors::{CustomDiagnostic, DiagnosticKind, FileDiagnostic}; +use noirc_errors::{CustomDiagnostic, DiagnosticKind}; use noirc_evaluator::brillig::BrilligOptions; use noirc_evaluator::create_program; use noirc_evaluator::errors::RuntimeError; use noirc_evaluator::ssa::{SsaLogging, SsaProgramArtifact}; use noirc_frontend::debug::build_debug_crate_file; use noirc_frontend::elaborator::{FrontendOptions, UnstableFeature}; -use noirc_frontend::hir::def_map::{Contract, CrateDefMap}; use noirc_frontend::hir::Context; +use noirc_frontend::hir::def_map::{Contract, CrateDefMap}; use noirc_frontend::monomorphization::{ errors::MonomorphizationError, monomorphize, monomorphize_debug, }; @@ -133,20 +133,16 @@ pub struct CompileOptions { #[arg(long)] pub skip_underconstrained_check: bool, - /// Flag to turn on the compiler check for missing Brillig call constraints. - /// Warning: This can degrade compilation speed but will also find some correctness errors. + /// Flag to turn off the compiler check for missing Brillig call constraints. + /// Warning: This can improve compilation speed but can also lead to correctness errors. /// This check should always be run on production code. #[arg(long)] - pub enable_brillig_constraints_check: bool, + pub skip_brillig_constraints_check: bool, /// Flag to turn on extra Brillig bytecode to be generated to guard against invalid states in testing. #[arg(long, hide = true)] pub enable_brillig_debug_assertions: bool, - /// Hidden Brillig call check flag to maintain CI compatibility (currently ignored) - #[arg(long, hide = true)] - pub skip_brillig_constraints_check: bool, - /// Flag to turn on the lookback feature of the Brillig call constraints /// check, allowing tracking argument values before the call happens preventing /// certain rare false positives (leads to a slowdown on large rollout functions) @@ -227,8 +223,8 @@ impl From for CompileError { } } -impl From for FileDiagnostic { - fn from(error: CompileError) -> FileDiagnostic { +impl From for CustomDiagnostic { + fn from(error: CompileError) -> CustomDiagnostic { match error { CompileError::RuntimeError(err) => err.into(), CompileError::MonomorphizationError(err) => err.into(), @@ -237,10 +233,10 @@ impl From for FileDiagnostic { } /// Helper type used to signify where only warnings are expected in file diagnostics -pub type Warnings = Vec; +pub type Warnings = Vec; /// Helper type used to signify where errors or warnings are expected in file diagnostics -pub type ErrorsAndWarnings = Vec; +pub type ErrorsAndWarnings = Vec; /// Helper type for connecting a compilation artifact to the errors or warnings which were produced during compilation. pub type CompilationResult = Result<(T, Warnings), ErrorsAndWarnings>; @@ -350,24 +346,16 @@ pub fn check_crate( ) -> CompilationResult<()> { let diagnostics = CrateDefMap::collect_defs(crate_id, context, options.frontend_options()); let crate_files = context.crate_files(&crate_id); - let warnings_and_errors: Vec = diagnostics - .into_iter() - .map(|error| { - let location = error.location(); - let diagnostic = CustomDiagnostic::from(&error); - diagnostic.in_file(location.file) - }) + let warnings_and_errors: Vec = diagnostics + .iter() + .map(CustomDiagnostic::from) .filter(|diagnostic| { // We filter out any warnings if they're going to be ignored later on to free up memory. - !options.silence_warnings || diagnostic.diagnostic.kind != DiagnosticKind::Warning + !options.silence_warnings || diagnostic.kind != DiagnosticKind::Warning }) .filter(|error| { // Only keep warnings from the crate we are checking - if error.diagnostic.is_warning() { - crate_files.contains(&error.file_id) - } else { - true - } + if error.is_warning() { crate_files.contains(&error.file) } else { true } }) .collect(); @@ -405,16 +393,16 @@ pub fn compile_main( // TODO(#2155): This error might be a better to exist in Nargo let err = CustomDiagnostic::from_message( "cannot compile crate into a program as it does not contain a `main` function", - ) - .in_file(FileId::default()); + FileId::default(), + ); vec![err] })?; let compiled_program = compile_no_check(context, options, main, cached_program, options.force_compile) - .map_err(FileDiagnostic::from)?; + .map_err(|error| vec![CustomDiagnostic::from(error)])?; - let compilation_warnings = vecmap(compiled_program.warnings.clone(), FileDiagnostic::from); + let compilation_warnings = vecmap(compiled_program.warnings.clone(), CustomDiagnostic::from); if options.deny_warnings && !compilation_warnings.is_empty() { return Err(compilation_warnings); } @@ -443,14 +431,16 @@ pub fn compile_contract( let mut errors = warnings; if contracts.len() > 1 { - let err = CustomDiagnostic::from_message("Packages are limited to a single contract") - .in_file(FileId::default()); + let err = CustomDiagnostic::from_message( + "Packages are limited to a single contract", + FileId::default(), + ); return Err(vec![err]); } else if contracts.is_empty() { let err = CustomDiagnostic::from_message( "cannot compile crate into a contract as it does not contain any contracts", - ) - .in_file(FileId::default()); + FileId::default(), + ); return Err(vec![err]); }; @@ -487,12 +477,8 @@ pub fn compile_contract( } /// True if there are (non-warning) errors present and we should halt compilation -fn has_errors(errors: &[FileDiagnostic], deny_warnings: bool) -> bool { - if deny_warnings { - !errors.is_empty() - } else { - errors.iter().any(|error| error.diagnostic.is_error()) - } +fn has_errors(errors: &[CustomDiagnostic], deny_warnings: bool) -> bool { + if deny_warnings { !errors.is_empty() } else { errors.iter().any(|error| error.is_error()) } } /// Compile all of the functions associated with a Noir contract. @@ -529,7 +515,7 @@ fn compile_contract_inner( let function = match compile_no_check(context, &options, function_id, None, true) { Ok(function) => function, Err(new_error) => { - errors.push(FileDiagnostic::from(new_error)); + errors.push(new_error.into()); continue; } }; @@ -708,7 +694,7 @@ pub fn compile_no_check( skip_underconstrained_check: options.skip_underconstrained_check, enable_brillig_constraints_check_lookback: options .enable_brillig_constraints_check_lookback, - enable_brillig_constraints_check: options.enable_brillig_constraints_check, + skip_brillig_constraints_check: options.skip_brillig_constraints_check, inliner_aggressiveness: options.inliner_aggressiveness, max_bytecode_increase_percent: options.max_bytecode_increase_percent, }; diff --git a/compiler/noirc_driver/src/program.rs b/compiler/noirc_driver/src/program.rs index 4b4d6662e8e..b3d545339fc 100644 --- a/compiler/noirc_driver/src/program.rs +++ b/compiler/noirc_driver/src/program.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use acvm::{acir::circuit::Program, FieldElement}; +use acvm::{FieldElement, acir::circuit::Program}; use fm::FileId; use noirc_errors::debug_info::DebugInfo; diff --git a/compiler/noirc_driver/tests/contracts.rs b/compiler/noirc_driver/tests/contracts.rs index c3041292352..0732a7728ca 100644 --- a/compiler/noirc_driver/tests/contracts.rs +++ b/compiler/noirc_driver/tests/contracts.rs @@ -1,9 +1,9 @@ use std::path::Path; use fm::FileId; -use noirc_driver::{file_manager_with_stdlib, prepare_crate, CompileOptions, ErrorsAndWarnings}; +use noirc_driver::{CompileOptions, ErrorsAndWarnings, file_manager_with_stdlib, prepare_crate}; use noirc_errors::CustomDiagnostic; -use noirc_frontend::hir::{def_map::parse_file, Context}; +use noirc_frontend::hir::{Context, def_map::parse_file}; #[test] fn reject_crates_containing_multiple_contracts() -> Result<(), ErrorsAndWarnings> { @@ -33,8 +33,10 @@ contract Bar {}"; assert_eq!( errors, - vec![CustomDiagnostic::from_message("Packages are limited to a single contract") - .in_file(FileId::default())], + vec![CustomDiagnostic::from_message( + "Packages are limited to a single contract", + FileId::default() + )], "stdlib is producing warnings" ); diff --git a/compiler/noirc_driver/tests/stdlib_warnings.rs b/compiler/noirc_driver/tests/stdlib_warnings.rs index e290842480d..411ea68fea7 100644 --- a/compiler/noirc_driver/tests/stdlib_warnings.rs +++ b/compiler/noirc_driver/tests/stdlib_warnings.rs @@ -1,7 +1,7 @@ use std::path::Path; -use noirc_driver::{file_manager_with_stdlib, prepare_crate, ErrorsAndWarnings}; -use noirc_frontend::hir::{def_map::parse_file, Context}; +use noirc_driver::{ErrorsAndWarnings, file_manager_with_stdlib, prepare_crate}; +use noirc_frontend::hir::{Context, def_map::parse_file}; #[test] fn stdlib_does_not_produce_constant_warnings() -> Result<(), ErrorsAndWarnings> { diff --git a/compiler/noirc_errors/src/debug_info.rs b/compiler/noirc_errors/src/debug_info.rs index a5e12b37712..4d25973835d 100644 --- a/compiler/noirc_errors/src/debug_info.rs +++ b/compiler/noirc_errors/src/debug_info.rs @@ -1,16 +1,16 @@ -use acvm::acir::circuit::brillig::BrilligFunctionId; use acvm::acir::circuit::BrilligOpcodeLocation; use acvm::acir::circuit::OpcodeLocation; +use acvm::acir::circuit::brillig::BrilligFunctionId; use acvm::compiler::AcirTransformationMap; use base64::Engine; +use flate2::Compression; use flate2::read::DeflateDecoder; use flate2::write::DeflateEncoder; -use flate2::Compression; use serde::Deserializer; use serde::Serializer; -use serde_with::serde_as; use serde_with::DisplayFromStr; +use serde_with::serde_as; use std::collections::BTreeMap; use std::io::Read; use std::io::Write; @@ -19,7 +19,7 @@ use std::mem; use crate::Location; use noirc_printable_type::PrintableType; use serde::{ - de::Error as DeserializationError, ser::Error as SerializationError, Deserialize, Serialize, + Deserialize, Serialize, de::Error as DeserializationError, ser::Error as SerializationError, }; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, Deserialize, Serialize)] diff --git a/compiler/noirc_errors/src/lib.rs b/compiler/noirc_errors/src/lib.rs index 146217f91a0..91d121603ba 100644 --- a/compiler/noirc_errors/src/lib.rs +++ b/compiler/noirc_errors/src/lib.rs @@ -8,21 +8,3 @@ mod position; pub mod reporter; pub use position::{Located, Location, Position, Span, Spanned}; pub use reporter::{CustomDiagnostic, DiagnosticKind}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FileDiagnostic { - pub file_id: fm::FileId, - pub diagnostic: CustomDiagnostic, -} - -impl FileDiagnostic { - pub fn new(file_id: fm::FileId, diagnostic: CustomDiagnostic) -> FileDiagnostic { - FileDiagnostic { file_id, diagnostic } - } -} - -impl From for Vec { - fn from(value: FileDiagnostic) -> Self { - vec![value] - } -} diff --git a/compiler/noirc_errors/src/reporter.rs b/compiler/noirc_errors/src/reporter.rs index e516f690ddc..d406e897d65 100644 --- a/compiler/noirc_errors/src/reporter.rs +++ b/compiler/noirc_errors/src/reporter.rs @@ -1,6 +1,6 @@ use std::io::IsTerminal; -use crate::{FileDiagnostic, Location, Span}; +use crate::{Location, Span}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::Files; use codespan_reporting::term; @@ -8,6 +8,7 @@ use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CustomDiagnostic { + pub file: fm::FileId, pub message: String, pub secondaries: Vec, pub notes: Vec, @@ -35,8 +36,9 @@ pub struct ReportedErrors { } impl CustomDiagnostic { - pub fn from_message(msg: &str) -> CustomDiagnostic { + pub fn from_message(msg: &str, file: fm::FileId) -> CustomDiagnostic { Self { + file, message: msg.to_owned(), secondaries: Vec::new(), notes: Vec::new(), @@ -54,6 +56,7 @@ impl CustomDiagnostic { kind: DiagnosticKind, ) -> CustomDiagnostic { CustomDiagnostic { + file: secondary_location.file, message: primary_message, secondaries: vec![CustomLabel::new(secondary_message, secondary_location)], notes: Vec::new(), @@ -109,6 +112,7 @@ impl CustomDiagnostic { secondary_location: Location, ) -> CustomDiagnostic { CustomDiagnostic { + file: secondary_location.file, message: primary_message, secondaries: vec![CustomLabel::new(secondary_message, secondary_location)], notes: Vec::new(), @@ -119,10 +123,6 @@ impl CustomDiagnostic { } } - pub fn in_file(self, file_id: fm::FileId) -> FileDiagnostic { - FileDiagnostic::new(file_id, self) - } - pub fn with_call_stack(mut self, call_stack: Vec) -> Self { self.call_stack = call_stack; self @@ -185,16 +185,16 @@ impl CustomLabel { /// of diagnostics that were errors. pub fn report_all<'files>( files: &'files impl Files<'files, FileId = fm::FileId>, - diagnostics: &[FileDiagnostic], + diagnostics: &[CustomDiagnostic], deny_warnings: bool, silence_warnings: bool, ) -> ReportedErrors { // Report warnings before any errors let (warnings_and_bugs, mut errors): (Vec<_>, _) = - diagnostics.iter().partition(|item| !item.diagnostic.is_error()); + diagnostics.iter().partition(|item| !item.is_error()); let (warnings, mut bugs): (Vec<_>, _) = - warnings_and_bugs.iter().partition(|item| item.diagnostic.is_warning()); + warnings_and_bugs.iter().partition(|item| item.is_warning()); let mut diagnostics = if silence_warnings { Vec::new() } else { warnings }; diagnostics.append(&mut bugs); diagnostics.append(&mut errors); @@ -205,14 +205,14 @@ pub fn report_all<'files>( ReportedErrors { error_count } } -impl FileDiagnostic { +impl CustomDiagnostic { /// Print the report; return true if it was an error. pub fn report<'files>( &self, files: &'files impl Files<'files, FileId = fm::FileId>, deny_warnings: bool, ) -> bool { - report(files, &self.diagnostic, deny_warnings) + report(files, self, deny_warnings) } } diff --git a/compiler/noirc_evaluator/src/acir/acir_variable.rs b/compiler/noirc_evaluator/src/acir/acir_variable.rs index a19edd3eb90..b8f5edaa3cd 100644 --- a/compiler/noirc_evaluator/src/acir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/acir/acir_variable.rs @@ -1,13 +1,13 @@ use acvm::{ + BlackBoxFunctionSolver, acir::{ + AcirField, BlackBoxFunc, circuit::{ - opcodes::{AcirFunctionId, BlockId, BlockType, MemOp}, AssertionPayload, ExpressionOrMemory, ExpressionWidth, Opcode, + opcodes::{AcirFunctionId, BlockId, BlockType, MemOp}, }, native_types::{Expression, Witness}, - AcirField, BlackBoxFunc, }, - BlackBoxFunctionSolver, }; use fxhash::FxHashMap as HashMap; use iter_extended::{try_vecmap, vecmap}; @@ -22,7 +22,7 @@ use crate::ssa::ir::{ use super::big_int::BigIntContext; use super::generated_acir::{BrilligStdlibFunc, GeneratedAcir, PLACEHOLDER_BRILLIG_INDEX}; -use super::{brillig_directive, AcirDynamicArray, AcirValue}; +use super::{AcirDynamicArray, AcirValue, brillig_directive}; #[derive(Clone, Debug, PartialEq, Eq, Hash)] /// High level Type descriptor for Variables. diff --git a/compiler/noirc_evaluator/src/acir/black_box.rs b/compiler/noirc_evaluator/src/acir/black_box.rs index 0f7eba69150..a75d53cf10a 100644 --- a/compiler/noirc_evaluator/src/acir/black_box.rs +++ b/compiler/noirc_evaluator/src/acir/black_box.rs @@ -1,9 +1,9 @@ use acvm::{ + BlackBoxFunctionSolver, acir::{ - circuit::opcodes::{ConstantOrWitnessEnum, FunctionInput}, AcirField, BlackBoxFunc, + circuit::opcodes::{ConstantOrWitnessEnum, FunctionInput}, }, - BlackBoxFunctionSolver, }; use iter_extended::vecmap; use num_bigint::BigUint; @@ -11,8 +11,8 @@ use num_bigint::BigUint; use crate::errors::{InternalError, RuntimeError}; use super::{ - acir_variable::{AcirContext, AcirVar}, AcirValue, + acir_variable::{AcirContext, AcirVar}, }; impl> AcirContext { diff --git a/compiler/noirc_evaluator/src/acir/brillig_call.rs b/compiler/noirc_evaluator/src/acir/brillig_call.rs index f027a7b62f8..020c60968a1 100644 --- a/compiler/noirc_evaluator/src/acir/brillig_call.rs +++ b/compiler/noirc_evaluator/src/acir/brillig_call.rs @@ -1,12 +1,12 @@ use acvm::{ + BlackBoxFunctionSolver, acir::{ + AcirField, brillig::Opcode as BrilligOpcode, circuit::brillig::{BrilligFunctionId, BrilligInputs, BrilligOutputs}, native_types::{Expression, Witness}, - AcirField, }, - brillig_vm::{MemoryValue, VMStatus, VM}, - BlackBoxFunctionSolver, + brillig_vm::{MemoryValue, VM, VMStatus}, }; use iter_extended::{try_vecmap, vecmap}; diff --git a/compiler/noirc_evaluator/src/acir/brillig_directive.rs b/compiler/noirc_evaluator/src/acir/brillig_directive.rs index 89fc7f1eda5..5fab9e34523 100644 --- a/compiler/noirc_evaluator/src/acir/brillig_directive.rs +++ b/compiler/noirc_evaluator/src/acir/brillig_directive.rs @@ -1,9 +1,9 @@ use acvm::acir::{ + AcirField, brillig::{ BinaryFieldOp, BinaryIntOp, BitSize, HeapVector, IntegerBitSize, MemoryAddress, Opcode as BrilligOpcode, }, - AcirField, }; use crate::brillig::brillig_ir::artifact::GeneratedBrillig; diff --git a/compiler/noirc_evaluator/src/acir/generated_acir.rs b/compiler/noirc_evaluator/src/acir/generated_acir.rs index e20028e56df..25b4771048c 100644 --- a/compiler/noirc_evaluator/src/acir/generated_acir.rs +++ b/compiler/noirc_evaluator/src/acir/generated_acir.rs @@ -3,21 +3,21 @@ use std::collections::BTreeMap; use acvm::acir::{ + AcirField, BlackBoxFunc, circuit::{ + AssertionPayload, BrilligOpcodeLocation, ErrorSelector, OpcodeLocation, brillig::{BrilligFunctionId, BrilligInputs, BrilligOutputs}, opcodes::{BlackBoxFuncCall, FunctionInput, Opcode as AcirOpcode}, - AssertionPayload, BrilligOpcodeLocation, ErrorSelector, OpcodeLocation, }, native_types::{Expression, Witness}, - AcirField, BlackBoxFunc, }; use super::brillig_directive; use crate::{ + ErrorType, brillig::brillig_ir::artifact::GeneratedBrillig, errors::{InternalError, RuntimeError, SsaReport}, ssa::ir::call_stack::CallStack, - ErrorType, }; use iter_extended::vecmap; diff --git a/compiler/noirc_evaluator/src/acir/mod.rs b/compiler/noirc_evaluator/src/acir/mod.rs index ac16afb47f0..a2c4913b5e7 100644 --- a/compiler/noirc_evaluator/src/acir/mod.rs +++ b/compiler/noirc_evaluator/src/acir/mod.rs @@ -5,15 +5,15 @@ use std::collections::{BTreeMap, HashSet}; use std::fmt::Debug; use acvm::acir::{ + BlackBoxFunc, circuit::{ + AssertionPayload, ErrorSelector, ExpressionWidth, OpcodeLocation, brillig::{BrilligBytecode, BrilligFunctionId}, opcodes::{AcirFunctionId, BlockType}, - AssertionPayload, ErrorSelector, ExpressionWidth, OpcodeLocation, }, native_types::Witness, - BlackBoxFunc, }; -use acvm::{acir::circuit::opcodes::BlockId, acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField, acir::circuit::opcodes::BlockId}; use bn254_blackbox_solver::Bn254BlackBoxSolver; use iter_extended::{try_vecmap, vecmap}; use noirc_frontend::monomorphization::ast::InlineType; @@ -25,12 +25,12 @@ mod brillig_call; mod brillig_directive; mod generated_acir; -use crate::brillig::brillig_gen::gen_brillig_for; use crate::brillig::BrilligOptions; +use crate::brillig::brillig_gen::gen_brillig_for; use crate::brillig::{ + Brillig, brillig_gen::brillig_fn::FunctionContext as BrilligFunctionContext, brillig_ir::artifact::{BrilligParameter, GeneratedBrillig}, - Brillig, }; use crate::errors::{InternalError, InternalWarning, RuntimeError, SsaReport}; use crate::ssa::ir::instruction::Hint; @@ -51,7 +51,7 @@ use crate::ssa::{ }, ssa_gen::Ssa, }; -use acir_variable::{power_of_two, AcirContext, AcirType, AcirVar}; +use acir_variable::{AcirContext, AcirType, AcirVar, power_of_two}; use generated_acir::BrilligStdlibFunc; pub(crate) use generated_acir::GeneratedAcir; use noirc_frontend::hir_def::types::Type as HirType; @@ -2902,15 +2902,15 @@ fn can_omit_element_sizes_array(array_typ: &Type) -> bool { mod test { use acvm::{ + FieldElement, acir::{ circuit::{ + ExpressionWidth, Opcode, OpcodeLocation, brillig::BrilligFunctionId, opcodes::{AcirFunctionId, BlackBoxFuncCall}, - ExpressionWidth, Opcode, OpcodeLocation, }, native_types::Witness, }, - FieldElement, }; use noirc_errors::Location; use noirc_frontend::monomorphization::ast::InlineType; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen.rs index 141b4f58408..64160528148 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen.rs @@ -12,11 +12,11 @@ use fxhash::FxHashMap as HashMap; use self::{brillig_block::BrilligBlock, brillig_fn::FunctionContext}; use super::{ + Brillig, BrilligOptions, BrilligVariable, ValueId, brillig_ir::{ - artifact::{BrilligArtifact, BrilligParameter, GeneratedBrillig, Label}, BrilligContext, + artifact::{BrilligArtifact, BrilligParameter, GeneratedBrillig, Label}, }, - Brillig, BrilligOptions, BrilligVariable, ValueId, }; use crate::{ errors::InternalError, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 82414b760cf..cdc6df26240 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -1,14 +1,14 @@ use acvm::{ + AcirField, acir::{ - brillig::{BlackBoxOp, HeapVector, ValueOrArray}, BlackBoxFunc, + brillig::{BlackBoxOp, HeapVector, ValueOrArray}, }, - AcirField, }; use crate::brillig::brillig_ir::{ - brillig_variable::BrilligVariable, debug_show::DebugToString, registers::RegisterAllocator, - BrilligContext, + BrilligContext, brillig_variable::BrilligVariable, debug_show::DebugToString, + registers::RegisterAllocator, }; /// Transforms SSA's black box function calls into the corresponding brillig instructions @@ -83,7 +83,12 @@ pub(crate) fn convert_black_box_call { if let ( - [BrilligVariable::BrilligArray(public_key_x), BrilligVariable::BrilligArray(public_key_y), BrilligVariable::BrilligArray(signature), message], + [ + BrilligVariable::BrilligArray(public_key_x), + BrilligVariable::BrilligArray(public_key_y), + BrilligVariable::BrilligArray(signature), + message, + ], [BrilligVariable::SingleAddr(result_register)], ) = (function_arguments, function_results) { @@ -114,7 +119,12 @@ pub(crate) fn convert_black_box_call { if let ( - [BrilligVariable::BrilligArray(public_key_x), BrilligVariable::BrilligArray(public_key_y), BrilligVariable::BrilligArray(signature), message], + [ + BrilligVariable::BrilligArray(public_key_x), + BrilligVariable::BrilligArray(public_key_y), + BrilligVariable::BrilligArray(signature), + message, + ], [BrilligVariable::SingleAddr(result_register)], ) = (function_arguments, function_results) { @@ -168,7 +178,14 @@ pub(crate) fn convert_black_box_call { if let ( - [BrilligVariable::SingleAddr(input1_x), BrilligVariable::SingleAddr(input1_y), BrilligVariable::SingleAddr(input1_infinite), BrilligVariable::SingleAddr(input2_x), BrilligVariable::SingleAddr(input2_y), BrilligVariable::SingleAddr(input2_infinite)], + [ + BrilligVariable::SingleAddr(input1_x), + BrilligVariable::SingleAddr(input1_y), + BrilligVariable::SingleAddr(input1_infinite), + BrilligVariable::SingleAddr(input2_x), + BrilligVariable::SingleAddr(input2_y), + BrilligVariable::SingleAddr(input2_infinite), + ], [BrilligVariable::BrilligArray(result_array)], ) = (function_arguments, function_results) { @@ -202,7 +219,12 @@ pub(crate) fn convert_black_box_call {} BlackBoxFunc::BigIntAdd => { if let ( - [BrilligVariable::SingleAddr(lhs), BrilligVariable::SingleAddr(_lhs_modulus), BrilligVariable::SingleAddr(rhs), BrilligVariable::SingleAddr(_rhs_modulus)], + [ + BrilligVariable::SingleAddr(lhs), + BrilligVariable::SingleAddr(_lhs_modulus), + BrilligVariable::SingleAddr(rhs), + BrilligVariable::SingleAddr(_rhs_modulus), + ], [BrilligVariable::SingleAddr(output), BrilligVariable::SingleAddr(_modulus_id)], ) = (function_arguments, function_results) { @@ -219,7 +241,12 @@ pub(crate) fn convert_black_box_call { if let ( - [BrilligVariable::SingleAddr(lhs), BrilligVariable::SingleAddr(_lhs_modulus), BrilligVariable::SingleAddr(rhs), BrilligVariable::SingleAddr(_rhs_modulus)], + [ + BrilligVariable::SingleAddr(lhs), + BrilligVariable::SingleAddr(_lhs_modulus), + BrilligVariable::SingleAddr(rhs), + BrilligVariable::SingleAddr(_rhs_modulus), + ], [BrilligVariable::SingleAddr(output), BrilligVariable::SingleAddr(_modulus_id)], ) = (function_arguments, function_results) { @@ -236,7 +263,12 @@ pub(crate) fn convert_black_box_call { if let ( - [BrilligVariable::SingleAddr(lhs), BrilligVariable::SingleAddr(_lhs_modulus), BrilligVariable::SingleAddr(rhs), BrilligVariable::SingleAddr(_rhs_modulus)], + [ + BrilligVariable::SingleAddr(lhs), + BrilligVariable::SingleAddr(_lhs_modulus), + BrilligVariable::SingleAddr(rhs), + BrilligVariable::SingleAddr(_rhs_modulus), + ], [BrilligVariable::SingleAddr(output), BrilligVariable::SingleAddr(_modulus_id)], ) = (function_arguments, function_results) { @@ -253,7 +285,12 @@ pub(crate) fn convert_black_box_call { if let ( - [BrilligVariable::SingleAddr(lhs), BrilligVariable::SingleAddr(_lhs_modulus), BrilligVariable::SingleAddr(rhs), BrilligVariable::SingleAddr(_rhs_modulus)], + [ + BrilligVariable::SingleAddr(lhs), + BrilligVariable::SingleAddr(_lhs_modulus), + BrilligVariable::SingleAddr(rhs), + BrilligVariable::SingleAddr(_rhs_modulus), + ], [BrilligVariable::SingleAddr(output), BrilligVariable::SingleAddr(_modulus_id)], ) = (function_arguments, function_results) { @@ -333,7 +370,10 @@ pub(crate) fn convert_black_box_call { if let ( - [BrilligVariable::BrilligArray(input_array), BrilligVariable::BrilligArray(hash_values)], + [ + BrilligVariable::BrilligArray(input_array), + BrilligVariable::BrilligArray(hash_values), + ], [BrilligVariable::BrilligArray(result_array)], ) = (function_arguments, function_results) { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 08391ba8af5..d8f1f9d0997 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,11 +1,11 @@ use crate::brillig::brillig_ir::artifact::Label; use crate::brillig::brillig_ir::brillig_variable::{ - type_to_heap_value_type, BrilligArray, BrilligVariable, SingleAddrVariable, + BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable, type_to_heap_value_type, }; use crate::brillig::brillig_ir::registers::RegisterAllocator; use crate::brillig::brillig_ir::{ - BrilligBinaryOp, BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, BrilligBinaryOp, BrilligContext, ReservedRegisters, }; use crate::ssa::ir::call_stack::CallStack; use crate::ssa::ir::instruction::{ConstrainError, Hint}; @@ -21,7 +21,7 @@ use crate::ssa::ir::{ }; use acvm::acir::brillig::{MemoryAddress, ValueOrArray}; use acvm::brillig_vm::MEMORY_ADDRESSING_BIT_SIZE; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use iter_extended::vecmap; use num_bigint::BigUint; @@ -29,7 +29,7 @@ use std::collections::BTreeSet; use std::sync::Arc; use super::brillig_black_box::convert_black_box_call; -use super::brillig_block_variables::{allocate_value_with_type, BlockVariables}; +use super::brillig_block_variables::{BlockVariables, allocate_value_with_type}; use super::brillig_fn::FunctionContext; use super::brillig_globals::HoistedConstantsToBrilligGlobals; use super::constant_allocation::InstructionLocation; @@ -935,8 +935,64 @@ impl<'block, Registers: RegisterAllocator> BrilligBlock<'block, Registers> { Instruction::EnableSideEffectsIf { .. } => { unreachable!("enable_side_effects not supported by brillig") } - Instruction::IfElse { .. } => { - unreachable!("IfElse instructions should not be possible in brillig") + Instruction::IfElse { then_condition, then_value, else_condition: _, else_value } => { + let then_condition = self.convert_ssa_single_addr_value(*then_condition, dfg); + let then_value = self.convert_ssa_value(*then_value, dfg); + let else_value = self.convert_ssa_value(*else_value, dfg); + let result = self.variables.define_variable( + self.function_context, + self.brillig_context, + dfg.instruction_results(instruction_id)[0], + dfg, + ); + match (then_value, else_value) { + ( + BrilligVariable::SingleAddr(then_address), + BrilligVariable::SingleAddr(else_address), + ) => { + self.brillig_context.conditional_move_instruction( + then_condition, + then_address, + else_address, + result.extract_single_addr(), + ); + } + ( + BrilligVariable::BrilligArray(then_array), + BrilligVariable::BrilligArray(else_array), + ) => { + // Pointer to the array which result from the if-else + let pointer = self.brillig_context.allocate_register(); + self.brillig_context.conditional_move_instruction( + then_condition, + SingleAddrVariable::new_usize(then_array.pointer), + SingleAddrVariable::new_usize(else_array.pointer), + SingleAddrVariable::new_usize(pointer), + ); + let if_else_array = BrilligArray { pointer, size: then_array.size }; + // Copy the if-else array to the result + self.brillig_context + .call_array_copy_procedure(if_else_array, result.extract_array()); + } + ( + BrilligVariable::BrilligVector(then_vector), + BrilligVariable::BrilligVector(else_vector), + ) => { + // Pointer to the vector which result from the if-else + let pointer = self.brillig_context.allocate_register(); + self.brillig_context.conditional_move_instruction( + then_condition, + SingleAddrVariable::new_usize(then_vector.pointer), + SingleAddrVariable::new_usize(else_vector.pointer), + SingleAddrVariable::new_usize(pointer), + ); + let if_else_vector = BrilligVector { pointer }; + // Copy the if-else vector to the result + self.brillig_context + .call_vector_copy_procedure(if_else_vector, result.extract_vector()); + } + _ => unreachable!("ICE - then and else values must have the same type"), + } } Instruction::MakeArray { elements: array, typ } => { let value_id = dfg.instruction_results(instruction_id)[0]; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index 4cf8e921483..027994a11de 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -3,12 +3,12 @@ use fxhash::FxHashSet as HashSet; use crate::{ brillig::brillig_ir::{ + BrilligContext, brillig_variable::{ - get_bit_size_from_ssa_type, BrilligArray, BrilligVariable, BrilligVector, - SingleAddrVariable, + BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable, + get_bit_size_from_ssa_type, }, registers::RegisterAllocator, - BrilligContext, }, ssa::ir::{ dfg::DataFlowGraph, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index d2656354b56..6ff85b9ebe8 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -3,7 +3,7 @@ use iter_extended::vecmap; use crate::{ brillig::brillig_ir::{ artifact::BrilligParameter, - brillig_variable::{get_bit_size_from_ssa_type, BrilligVariable}, + brillig_variable::{BrilligVariable, get_bit_size_from_ssa_type}, }, ssa::ir::{ basic_block::BasicBlockId, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_globals.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_globals.rs index 5c955cbe4b3..317f763078e 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_globals.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_globals.rs @@ -8,7 +8,7 @@ use super::{ }; use crate::brillig::{Brillig, BrilligOptions, FunctionId}; use crate::{ - brillig::{brillig_ir::BrilligContext, ConstantAllocation, DataFlowGraph}, + brillig::{ConstantAllocation, DataFlowGraph, brillig_ir::BrilligContext}, ssa::ir::types::NumericType, ssa::opt::brillig_entry_points::{build_inner_call_to_entry_points, get_brillig_entry_points}, }; @@ -147,11 +147,7 @@ impl BrilligGlobals { .iter() .filter_map( |(&value, &num_occurrences)| { - if num_occurrences > 1 { - Some(value) - } else { - None - } + if num_occurrences > 1 { Some(value) } else { None } }, ) .collect(); @@ -280,12 +276,12 @@ pub(crate) fn convert_ssa_globals( #[cfg(test)] mod tests { use acvm::{ - acir::brillig::{BitSize, IntegerBitSize, Opcode}, FieldElement, + acir::brillig::{BitSize, IntegerBitSize, Opcode}, }; use crate::brillig::{ - brillig_ir::registers::RegisterAllocator, BrilligOptions, GlobalSpace, LabelType, Ssa, + BrilligOptions, GlobalSpace, LabelType, Ssa, brillig_ir::registers::RegisterAllocator, }; use super::ConstantAllocation; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index b15259da072..6387dc3dd37 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -1,9 +1,9 @@ use acvm::acir::brillig::MemoryAddress; use crate::brillig::brillig_ir::{ + BrilligBinaryOp, brillig_variable::{BrilligVariable, BrilligVector, SingleAddrVariable}, registers::RegisterAllocator, - BrilligBinaryOp, }; use super::brillig_block::BrilligBlock; @@ -163,6 +163,7 @@ mod tests { use fxhash::FxHashMap as HashMap; use noirc_frontend::monomorphization::ast::InlineType; + use crate::brillig::ValueId; use crate::brillig::brillig_gen::brillig_block::BrilligBlock; use crate::brillig::brillig_gen::brillig_block_variables::BlockVariables; use crate::brillig::brillig_gen::brillig_fn::FunctionContext; @@ -174,8 +175,7 @@ mod tests { use crate::brillig::brillig_ir::tests::{ create_and_run_vm, create_context, create_entry_point_bytecode, }; - use crate::brillig::brillig_ir::{BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE}; - use crate::brillig::ValueId; + use crate::brillig::brillig_ir::{BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, BrilligContext}; use crate::ssa::function_builder::FunctionBuilder; use crate::ssa::ir::function::RuntimeType; use crate::ssa::ir::map::Id; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 95e6c5175b2..a0637e8e3c2 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -32,8 +32,8 @@ use registers::{RegisterAllocator, ScratchSpace}; use self::{artifact::BrilligArtifact, debug_show::DebugToString, registers::Stack}; use crate::ssa::ir::call_stack::CallStack; use acvm::{ - acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}, AcirField, + acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}, }; use debug_show::DebugShow; @@ -281,11 +281,11 @@ pub(crate) mod tests { ValueOrArray, }; use acvm::brillig_vm::brillig::HeapValueType; - use acvm::brillig_vm::{VMStatus, VM}; + use acvm::brillig_vm::{VM, VMStatus}; use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; - use crate::brillig::brillig_ir::{BrilligBinaryOp, BrilligContext}; use crate::brillig::BrilligOptions; + use crate::brillig::brillig_ir::{BrilligBinaryOp, BrilligContext}; use crate::ssa::ir::function::FunctionId; use super::artifact::{BrilligParameter, GeneratedBrillig, Label, LabelType}; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs index 7f510751cb1..42052c09230 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs @@ -2,8 +2,8 @@ use acvm::acir::brillig::Opcode as BrilligOpcode; use acvm::acir::circuit::ErrorSelector; use std::collections::{BTreeMap, HashMap}; -use crate::ssa::ir::{basic_block::BasicBlockId, call_stack::CallStack, function::FunctionId}; use crate::ErrorType; +use crate::ssa::ir::{basic_block::BasicBlockId, call_stack::CallStack, function::FunctionId}; use super::procedures::ProcedureId; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index 0bb18448670..2a46cae2d24 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -1,7 +1,7 @@ use acvm::{ - acir::{brillig::BitSize, AcirField}, - brillig_vm::brillig::{HeapValueType, MemoryAddress}, FieldElement, + acir::{AcirField, brillig::BitSize}, + brillig_vm::brillig::{HeapValueType, MemoryAddress}, }; use serde::{Deserialize, Serialize}; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs index 9f573543e2a..1fc37882e48 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs @@ -1,8 +1,8 @@ -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::{ - debug_show::DebugToString, instructions::BrilligBinaryOp, registers::RegisterAllocator, - BrilligContext, ReservedRegisters, + BrilligContext, ReservedRegisters, debug_show::DebugToString, instructions::BrilligBinaryOp, + registers::RegisterAllocator, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs index 4da3aa4d6d2..5036326fbc9 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs @@ -1,12 +1,12 @@ -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use crate::ssa::ir::function::FunctionId; use super::{ + BrilligBinaryOp, BrilligContext, ReservedRegisters, brillig_variable::{BrilligVariable, SingleAddrVariable}, debug_show::DebugToString, registers::{RegisterAllocator, Stack}, - BrilligBinaryOp, BrilligContext, ReservedRegisters, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs index 9512a60e699..388c5f7a343 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs @@ -1,19 +1,19 @@ use acvm::{ + AcirField, acir::{ brillig::{HeapVector, MemoryAddress}, circuit::ErrorSelector, }, - AcirField, }; use crate::ssa::ir::instruction::ErrorType; use super::{ + BrilligBinaryOp, BrilligContext, ReservedRegisters, artifact::BrilligParameter, brillig_variable::{BrilligArray, BrilligVariable, SingleAddrVariable}, debug_show::DebugToString, registers::RegisterAllocator, - BrilligBinaryOp, BrilligContext, ReservedRegisters, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index 42c13a3c235..3daf0486110 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -1,15 +1,15 @@ use acvm::acir::{ - brillig::{BlackBoxOp, IntegerBitSize}, AcirField, + brillig::{BlackBoxOp, IntegerBitSize}, }; use crate::brillig::brillig_ir::BrilligBinaryOp; use super::{ + BrilligContext, brillig_variable::{BrilligArray, SingleAddrVariable}, debug_show::DebugToString, registers::RegisterAllocator, - BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs index a34034bb550..2936aea486e 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs @@ -1,15 +1,15 @@ use acvm::{ - acir::brillig::{HeapArray, HeapVector, MemoryAddress, ValueOrArray}, AcirField, + acir::brillig::{HeapArray, HeapVector, MemoryAddress, ValueOrArray}, }; use crate::brillig::brillig_ir::BrilligBinaryOp; use super::{ + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, BrilligContext, ReservedRegisters, brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, debug_show::DebugToString, registers::RegisterAllocator, - BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs index f609c342288..a5dbc2811c3 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs @@ -1,7 +1,7 @@ -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; -use super::{debug_show::DebugToString, registers::RegisterAllocator, BrilligContext}; +use super::{BrilligContext, debug_show::DebugToString, registers::RegisterAllocator}; impl BrilligContext { /// This function moves values from a set of registers to another set of registers. @@ -126,15 +126,15 @@ impl LoopDetector { #[cfg(test)] mod tests { use acvm::{ - acir::brillig::{MemoryAddress, Opcode}, FieldElement, + acir::brillig::{MemoryAddress, Opcode}, }; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::{ brillig::{ - brillig_ir::{artifact::Label, registers::Stack, BrilligContext}, BrilligOptions, + brillig_ir::{BrilligContext, artifact::Label, registers::Stack}, }, ssa::ir::function::FunctionId, }; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 283c0d67eb8..c0b6492618c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -3,8 +3,8 @@ use super::BrilligBinaryOp; use crate::brillig::brillig_ir::ReservedRegisters; use acvm::{ - acir::brillig::{BlackBoxOp, HeapArray, HeapVector, MemoryAddress, ValueOrArray}, FieldElement, + acir::brillig::{BlackBoxOp, HeapArray, HeapVector, MemoryAddress, ValueOrArray}, }; /// Trait for converting values into debug-friendly strings. @@ -126,6 +126,24 @@ impl DebugShow { debug_println!(self.enable_debug_trace, " MOV {}, {}", destination, source); } + /// Emits a `conditional mov` instruction. + pub(crate) fn conditional_mov_instruction( + &self, + destination: MemoryAddress, + source_then: MemoryAddress, + source_else: MemoryAddress, + condition: MemoryAddress, + ) { + debug_println!( + self.enable_debug_trace, + " {} = MOV if {} then {}, else {}", + destination, + condition, + source_then, + source_else + ); + } + /// Emits a `cast` instruction. pub(crate) fn cast_instruction( &self, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 4a5be8bb19c..e1450f0f118 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -1,15 +1,15 @@ use crate::{brillig::BrilligOptions, ssa::ir::function::FunctionId}; use super::{ + BrilligBinaryOp, BrilligContext, ReservedRegisters, artifact::{BrilligArtifact, BrilligParameter}, brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, debug_show::DebugToString, registers::Stack, - BrilligBinaryOp, BrilligContext, ReservedRegisters, }; use acvm::acir::{ - brillig::{HeapVector, MemoryAddress}, AcirField, + brillig::{HeapVector, MemoryAddress}, }; pub(crate) const MAX_STACK_SIZE: usize = 16 * MAX_STACK_FRAME_SIZE; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index 9dd541c7180..fad9892cfb1 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -1,23 +1,23 @@ use acvm::{ + FieldElement, acir::{ + AcirField, brillig::{ BinaryFieldOp, BinaryIntOp, BitSize, BlackBoxOp, HeapValueType, HeapVector, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, }, - AcirField, }, - FieldElement, }; use crate::ssa::ir::function::FunctionId; use super::{ + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, BrilligContext, ReservedRegisters, artifact::{Label, UnresolvedJumpLocation}, brillig_variable::SingleAddrVariable, debug_show::DebugToString, procedures::ProcedureId, registers::RegisterAllocator, - BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; /// Low level instructions of the brillig IR, used by the brillig ir codegens and brillig_gen @@ -75,6 +75,28 @@ impl BrilligContext< ); } + /// Insert a conditional move instruction + pub(crate) fn conditional_move_instruction( + &mut self, + condition: SingleAddrVariable, + then_address: SingleAddrVariable, + else_address: SingleAddrVariable, + destination: SingleAddrVariable, + ) { + self.debug_show.conditional_mov_instruction( + destination.address, + then_address.address, + else_address.address, + condition.address, + ); + self.push_opcode(BrilligOpcode::ConditionalMov { + destination: destination.address, + source_a: then_address.address, + source_b: else_address.address, + condition: condition.address, + }); + } + fn binary( &mut self, lhs: SingleAddrVariable, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_copy.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_copy.rs index 0a6e8824223..cccd08fe2d5 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_copy.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_copy.rs @@ -1,13 +1,13 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, BrilligBinaryOp, BrilligContext, brillig_variable::{BrilligArray, SingleAddrVariable}, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligBinaryOp, BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_reverse.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_reverse.rs index a5a11d61bef..aa5d1cfeece 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_reverse.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_reverse.rs @@ -1,12 +1,12 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BrilligContext, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/check_max_stack_depth.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/check_max_stack_depth.rs index 4d5abe93420..fd8552903c7 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/check_max_stack_depth.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/check_max_stack_depth.rs @@ -2,11 +2,11 @@ use acvm::AcirField; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BrilligBinaryOp, BrilligContext, ReservedRegisters, brillig_variable::SingleAddrVariable, debug_show::DebugToString, entry_point::{MAX_STACK_FRAME_SIZE, MAX_STACK_SIZE}, registers::{RegisterAllocator, ScratchSpace}, - BrilligBinaryOp, BrilligContext, ReservedRegisters, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mem_copy.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mem_copy.rs index cdd99542483..9f3f1daa2ac 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mem_copy.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mem_copy.rs @@ -1,13 +1,13 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BrilligContext, brillig_variable::SingleAddrVariable, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs index 8e1761d0eee..a2d00786ff8 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs @@ -25,12 +25,12 @@ use vector_pop_back::compile_vector_pop_back_procedure; use vector_pop_front::compile_vector_pop_front_procedure; use vector_remove::compile_vector_remove_procedure; -use crate::brillig::{brillig_ir::AcirField, BrilligOptions}; +use crate::brillig::{BrilligOptions, brillig_ir::AcirField}; use super::{ + BrilligContext, artifact::{BrilligArtifact, Label}, debug_show::DebugToString, - BrilligContext, }; /// Procedures are a set of complex operations that are common in the noir language. diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs index 1c1a738509c..dced68922ef 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs @@ -1,13 +1,13 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; -use super::{prepare_vector_push::reallocate_vector_for_insertion, ProcedureId}; +use super::{ProcedureId, prepare_vector_push::reallocate_vector_for_insertion}; use crate::brillig::brillig_ir::{ + BrilligBinaryOp, BrilligContext, brillig_variable::{BrilligVector, SingleAddrVariable}, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligBinaryOp, BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs index 798cf2385e5..4d985ccb12b 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs @@ -1,13 +1,13 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BrilligBinaryOp, BrilligContext, brillig_variable::{BrilligVector, SingleAddrVariable}, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligBinaryOp, BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/revert_with_string.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/revert_with_string.rs index 83d7dfc618d..1601451ef50 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/revert_with_string.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/revert_with_string.rs @@ -2,9 +2,9 @@ use acvm::AcirField; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BrilligContext, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_copy.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_copy.rs index 6d2f9c4afb4..8e53fb8d01c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_copy.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_copy.rs @@ -1,13 +1,13 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, BrilligBinaryOp, BrilligContext, brillig_variable::{BrilligVector, SingleAddrVariable}, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligBinaryOp, BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_back.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_back.rs index bfc9d512852..bd71b39f9e7 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_back.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_back.rs @@ -1,13 +1,13 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BrilligBinaryOp, BrilligContext, brillig_variable::{BrilligVector, SingleAddrVariable}, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligBinaryOp, BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_front.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_front.rs index 49123ca2f50..8df8f1c6b12 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_front.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop_front.rs @@ -1,13 +1,13 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BrilligBinaryOp, BrilligContext, brillig_variable::{BrilligVector, SingleAddrVariable}, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligBinaryOp, BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs index 7abc43286ee..686fc74210a 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs @@ -1,13 +1,13 @@ use std::vec; -use acvm::{acir::brillig::MemoryAddress, AcirField}; +use acvm::{AcirField, acir::brillig::MemoryAddress}; use super::ProcedureId; use crate::brillig::brillig_ir::{ + BrilligBinaryOp, BrilligContext, brillig_variable::{BrilligVector, SingleAddrVariable}, debug_show::DebugToString, registers::{RegisterAllocator, ScratchSpace}, - BrilligBinaryOp, BrilligContext, }; impl BrilligContext { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs index 093c99dec3b..2fc7f6fc711 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs @@ -6,9 +6,9 @@ use iter_extended::vecmap; use crate::brillig::brillig_ir::entry_point::MAX_STACK_SIZE; use super::{ + BrilligContext, ReservedRegisters, brillig_variable::SingleAddrVariable, entry_point::{MAX_SCRATCH_SPACE, MAX_STACK_FRAME_SIZE}, - BrilligContext, ReservedRegisters, }; pub(crate) trait RegisterAllocator { diff --git a/compiler/noirc_evaluator/src/errors.rs b/compiler/noirc_evaluator/src/errors.rs index 202124f7931..deaefd40ae3 100644 --- a/compiler/noirc_evaluator/src/errors.rs +++ b/compiler/noirc_evaluator/src/errors.rs @@ -8,7 +8,7 @@ //! //! An Error of the latter is an error in the implementation of the compiler use iter_extended::vecmap; -use noirc_errors::{CustomDiagnostic as Diagnostic, FileDiagnostic, Location}; +use noirc_errors::{CustomDiagnostic, Location}; use noirc_frontend::signed_field::SignedField; use thiserror::Error; @@ -73,8 +73,8 @@ pub enum SsaReport { Bug(InternalBug), } -impl From for FileDiagnostic { - fn from(error: SsaReport) -> FileDiagnostic { +impl From for CustomDiagnostic { + fn from(error: SsaReport) -> CustomDiagnostic { match error { SsaReport::Warning(warning) => { let message = warning.to_string(); @@ -87,10 +87,10 @@ impl From for FileDiagnostic { }, }; let call_stack = vecmap(call_stack, |location| location); - let file_id = call_stack.last().map(|location| location.file).unwrap_or_default(); let location = call_stack.last().expect("Expected RuntimeError to have a location"); - let diagnostic = Diagnostic::simple_warning(message, secondary_message, *location); - diagnostic.with_call_stack(call_stack).in_file(file_id) + let diagnostic = + CustomDiagnostic::simple_warning(message, secondary_message, *location); + diagnostic.with_call_stack(call_stack) } SsaReport::Bug(bug) => { let message = bug.to_string(); @@ -104,10 +104,10 @@ impl From for FileDiagnostic { InternalBug::AssertFailed { call_stack } => ("As a result, the compiled circuit is ensured to fail. Other assertions may also fail during execution".to_string(), call_stack) }; let call_stack = vecmap(call_stack, |location| location); - let file_id = call_stack.last().map(|location| location.file).unwrap_or_default(); let location = call_stack.last().expect("Expected RuntimeError to have a location"); - let diagnostic = Diagnostic::simple_bug(message, secondary_message, *location); - diagnostic.with_call_stack(call_stack).in_file(file_id) + let diagnostic = + CustomDiagnostic::simple_bug(message, secondary_message, *location); + diagnostic.with_call_stack(call_stack) } } } @@ -181,20 +181,19 @@ impl RuntimeError { } } -impl From for FileDiagnostic { - fn from(error: RuntimeError) -> FileDiagnostic { +impl From for CustomDiagnostic { + fn from(error: RuntimeError) -> CustomDiagnostic { let call_stack = vecmap(error.call_stack(), |location| *location); - let file_id = call_stack.last().map(|location| location.file).unwrap_or_default(); let diagnostic = error.into_diagnostic(); - diagnostic.with_call_stack(call_stack).in_file(file_id) + diagnostic.with_call_stack(call_stack) } } impl RuntimeError { - fn into_diagnostic(self) -> Diagnostic { + fn into_diagnostic(self) -> CustomDiagnostic { match self { RuntimeError::InternalError(cause) => { - Diagnostic::simple_error( + CustomDiagnostic::simple_error( "Internal Consistency Evaluators Errors: \n This is likely a bug. Consider opening an issue at https://github.com/noir-lang/noir/issues".to_owned(), cause.to_string(), @@ -206,7 +205,7 @@ impl RuntimeError { let location = self.call_stack().last().expect("Expected RuntimeError to have a location"); - Diagnostic::simple_error( + CustomDiagnostic::simple_error( primary_message, "If attempting to fetch the length of a slice, try converting to an array. Slices only use dynamic lengths.".to_string(), *location, @@ -217,7 +216,7 @@ impl RuntimeError { let location = self.call_stack().last().unwrap_or_else(|| panic!("Expected RuntimeError to have a location. Error message: {message}")); - Diagnostic::simple_error(message, String::new(), *location) + CustomDiagnostic::simple_error(message, String::new(), *location) } } } diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index a516499a761..935918c6b7e 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -18,14 +18,14 @@ use crate::{ errors::{RuntimeError, SsaReport}, }; use acvm::{ + FieldElement, acir::{ circuit::{ - brillig::BrilligBytecode, Circuit, ErrorSelector, ExpressionWidth, - Program as AcirProgram, PublicInputs, + Circuit, ErrorSelector, ExpressionWidth, Program as AcirProgram, PublicInputs, + brillig::BrilligBytecode, }, native_types::Witness, }, - FieldElement, }; use ir::instruction::ErrorType; @@ -34,7 +34,7 @@ use noirc_errors::debug_info::{DebugFunctions, DebugInfo, DebugTypes, DebugVaria use noirc_frontend::ast::Visibility; use noirc_frontend::{hir_def::function::FunctionSignature, monomorphization::ast::Program}; use ssa_gen::Ssa; -use tracing::{span, Level}; +use tracing::{Level, span}; use crate::acir::{Artifacts, GeneratedAcir}; @@ -72,8 +72,8 @@ pub struct SsaEvaluatorOptions { /// Skip the check for under constrained values pub skip_underconstrained_check: bool, - /// Enable the missing Brillig call constraints check - pub enable_brillig_constraints_check: bool, + /// Skip the missing Brillig call constraints check + pub skip_brillig_constraints_check: bool, /// Enable the lookback feature of the Brillig call constraints /// check (prevents some rare false positives, leads to a slowdown @@ -143,7 +143,7 @@ pub(crate) fn optimize_into_acir( )); } - if options.enable_brillig_constraints_check { + if !options.skip_brillig_constraints_check { ssa_level_warnings.extend(time( "After Check for Missing Brillig Call Constraints", options.print_codegen_timings, @@ -211,6 +211,7 @@ fn optimize_all(builder: SsaBuilder, options: &SsaEvaluatorOptions) -> Result, // Map of argument value ids to the Brillig call ids employing them call_arguments: HashMap>, - // Maintains count of calls being tracked - tracking_count: usize, + // The set of calls currently being tracked + tracking: HashSet, // Opt-in to use the lookback feature (tracking the argument values // of a Brillig call before the call happens if their usage precedes // it). Can prevent certain false positives, at the cost of @@ -138,8 +138,6 @@ struct BrilligTaintedIds { array_elements: HashMap>, // Initial result value ids, along with element ids for arrays root_results: HashSet, - // The flag signaling that the call should be now tracked - tracking: bool, } #[derive(Clone, Debug)] @@ -195,7 +193,6 @@ impl BrilligTaintedIds { results: results_status, array_elements, root_results: HashSet::from_iter(results.iter().copied()), - tracking: false, } } @@ -394,23 +391,19 @@ impl DependencyContext { for argument in &arguments { if let Some(calls) = self.call_arguments.get(argument) { for call in calls { - if let Some(tainted_ids) = self.tainted.get_mut(call) { - tainted_ids.tracking = true; - self.tracking_count += 1; + if self.tainted.contains_key(call) { + self.tracking.insert(*call); } } } } } - if let Some(tainted_ids) = self.tainted.get_mut(instruction) { - if !tainted_ids.tracking { - tainted_ids.tracking = true; - self.tracking_count += 1; - } + if self.tainted.contains_key(instruction) { + self.tracking.insert(*instruction); } // We can skip over instructions while nothing is being tracked - if self.tracking_count > 0 { + if !self.tracking.is_empty() { let mut results = Vec::new(); // Collect non-constant instruction results @@ -524,7 +517,7 @@ impl DependencyContext { // results involving the array in question, to properly // populate the array element tainted sets Instruction::ArrayGet { array, index } => { - self.process_array_get(function, *array, *index, &results); + self.process_array_get(*array, *index, &results, function); // Record all the used arguments as parents of the results self.update_children(&arguments, &results); } @@ -563,7 +556,10 @@ impl DependencyContext { .tainted .keys() .map(|brillig_call| { - trace!("tainted structure for {}: {:?}", brillig_call, self.tainted[brillig_call]); + trace!( + "tainted structure for {:?}: {:?}", + brillig_call, self.tainted[brillig_call] + ); SsaReport::Bug(InternalBug::UncheckedBrilligCall { call_stack: function.dfg.get_instruction_call_stack(*brillig_call), }) @@ -587,8 +583,8 @@ impl DependencyContext { self.side_effects_condition.map(|v| parents.insert(v)); // Don't update sets for the calls not yet being tracked - for (_, tainted_ids) in self.tainted.iter_mut() { - if tainted_ids.tracking { + for call in &self.tracking { + if let Some(tainted_ids) = self.tainted.get_mut(call) { tainted_ids.update_children(&parents, children); } } @@ -605,15 +601,15 @@ impl DependencyContext { .collect(); // Skip untracked calls - for (_, tainted_ids) in self.tainted.iter_mut() { - if tainted_ids.tracking { + for call in &self.tracking { + if let Some(tainted_ids) = self.tainted.get_mut(call) { tainted_ids.store_partial_constraints(&constrained_values); } } - self.tainted.retain(|_, tainted_ids| { + self.tainted.retain(|call, tainted_ids| { if tainted_ids.check_constrained() { - self.tracking_count -= 1; + self.tracking.remove(call); false } else { true @@ -624,10 +620,10 @@ impl DependencyContext { /// Process ArrayGet instruction for tracked Brillig calls fn process_array_get( &mut self, - function: &Function, array: ValueId, index: ValueId, element_results: &[ValueId], + function: &Function, ) { use acvm::acir::AcirField; @@ -635,8 +631,8 @@ impl DependencyContext { if let Some(value) = function.dfg.get_numeric_constant(index) { if let Some(index) = value.try_to_u32() { // Skip untracked calls - for (_, tainted_ids) in self.tainted.iter_mut() { - if tainted_ids.tracking { + for call in &self.tracking { + if let Some(tainted_ids) = self.tainted.get_mut(call) { tainted_ids.process_array_get(array, index as usize, element_results); } } diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index c2a3c346d28..95944129c4e 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -2,7 +2,7 @@ pub(crate) mod data_bus; use std::{borrow::Cow, collections::BTreeMap, sync::Arc}; -use acvm::{acir::circuit::ErrorSelector, FieldElement}; +use acvm::{FieldElement, acir::circuit::ErrorSelector}; use noirc_errors::Location; use noirc_frontend::hir_def::types::Type as HirType; use noirc_frontend::monomorphization::ast::InlineType; @@ -588,7 +588,7 @@ impl std::ops::Index for FunctionBuilder { mod tests { use std::sync::Arc; - use acvm::{acir::AcirField, FieldElement}; + use acvm::{FieldElement, acir::AcirField}; use crate::ssa::ir::{ instruction::{Endian, Intrinsic}, diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 62512ff4fdc..132985830eb 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -18,12 +18,12 @@ use super::{ value::{Value, ValueId}, }; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use fxhash::FxHashMap as HashMap; use iter_extended::vecmap; use serde::{Deserialize, Serialize}; -use serde_with::serde_as; use serde_with::DisplayFromStr; +use serde_with::serde_as; /// The DataFlowGraph contains most of the actual data in a function including /// its blocks, instructions, and values. This struct is largely responsible for @@ -239,10 +239,9 @@ impl DataFlowGraph { instruction, Instruction::IncrementRc { .. } | Instruction::DecrementRc { .. } ), - RuntimeType::Brillig(_) => !matches!( - instruction, - Instruction::EnableSideEffectsIf { .. } | Instruction::IfElse { .. } - ), + RuntimeType::Brillig(_) => { + !matches!(instruction, Instruction::EnableSideEffectsIf { .. }) + } } } @@ -377,6 +376,11 @@ impl DataFlowGraph { } } + /// Replace an existing instruction with a new one. + pub(crate) fn set_instruction(&mut self, id: InstructionId, instruction: Instruction) { + self.instructions[id] = instruction; + } + /// Set the value of value_to_replace to refer to the value referred to by new_value. /// /// This is the preferred method to call for optimizations simplifying diff --git a/compiler/noirc_evaluator/src/ssa/ir/dom.rs b/compiler/noirc_evaluator/src/ssa/ir/dom.rs index 49862b49be3..a6f878dafbf 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dom.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dom.rs @@ -292,8 +292,8 @@ mod tests { } // Testing setup for a function with an unreachable block2 - fn unreachable_node_setup( - ) -> (DominatorTree, BasicBlockId, BasicBlockId, BasicBlockId, BasicBlockId) { + fn unreachable_node_setup() + -> (DominatorTree, BasicBlockId, BasicBlockId, BasicBlockId, BasicBlockId) { // func() { // block0(cond: u1): // jmpif v0 block2() block3() diff --git a/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs b/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs index 9e4557e06a6..13b5ead5eb6 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs @@ -79,6 +79,13 @@ impl<'f> FunctionInserter<'f> { (instruction, self.function.dfg.get_instruction_call_stack_id(id)) } + /// Get an instruction, map all its values, and replace it with the resolved instruction. + pub(crate) fn map_instruction_in_place(&mut self, id: InstructionId) { + let mut instruction = self.function.dfg[id].clone(); + instruction.map_values_mut(|id| self.resolve(id)); + self.function.dfg.set_instruction(id, instruction); + } + /// Maps a terminator in place, replacing any ValueId in the terminator with the /// resolved version of that value id from this FunctionInserter's internal value mapping. pub(crate) fn map_terminator_in_place(&mut self, block: BasicBlockId) { @@ -251,4 +258,22 @@ impl<'f> FunctionInserter<'f> { self.values.entry(*param).or_insert(*new_param); } } + + /// Merge the internal mapping into the given mapping + /// The merge is guaranteed to be coherent because ambiguous cases are prevented + pub(crate) fn extract_mapping(&self, mapping: &mut HashMap) { + for (k, v) in &self.values { + if mapping.contains_key(k) { + unreachable!("cannot merge key"); + } + if mapping.contains_key(v) { + unreachable!("cannot merge value"); + } + mapping.insert(*k, *v); + } + } + + pub(crate) fn set_mapping(&mut self, mapping: HashMap) { + self.values = mapping; + } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 63172d07d82..1bef9079eb8 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -3,9 +3,9 @@ use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; use acvm::{ - acir::AcirField, - acir::{circuit::ErrorSelector, BlackBoxFunc}, FieldElement, + acir::AcirField, + acir::{BlackBoxFunc, circuit::ErrorSelector}, }; use fxhash::FxHasher64; use iter_extended::vecmap; @@ -1003,11 +1003,7 @@ impl Instruction { // // In order for the truncation to be a noop, we then require `max_quotient_bits < bit_size`. let max_quotient_bits = max_numerator_bits - divisor_bits; - if max_quotient_bits < *bit_size { - SimplifiedTo(*value) - } else { - None - } + if max_quotient_bits < *bit_size { SimplifiedTo(*value) } else { None } } _ => None, @@ -1036,11 +1032,7 @@ impl Instruction { Instruction::DecrementRc { .. } => None, Instruction::RangeCheck { value, max_bit_size, .. } => { let max_potential_bits = dfg.get_value_max_num_bits(*value); - if max_potential_bits <= *max_bit_size { - Remove - } else { - None - } + if max_potential_bits <= *max_bit_size { Remove } else { None } } Instruction::IfElse { then_condition, then_value, else_condition, else_value } => { let then_condition = dfg.resolve(*then_condition); diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs index a67c2d7a0f8..1ec2e33ee8d 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs @@ -1,4 +1,4 @@ -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use num_traits::ToPrimitive as _; use serde::{Deserialize, Serialize}; @@ -625,8 +625,8 @@ mod test { use proptest::prelude::*; use super::{ - convert_signed_integer_to_field_element, truncate_field, - try_convert_field_element_to_signed_integer, BinaryOp, + BinaryOp, convert_signed_integer_to_field_element, truncate_field, + try_convert_field_element_to_signed_integer, }; use acvm::{AcirField, FieldElement}; use num_bigint::BigUint; diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index cd83dd9ba78..d32a562a037 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -2,8 +2,8 @@ use fxhash::FxHashMap as HashMap; use std::{collections::VecDeque, sync::Arc}; use acvm::{ - acir::{AcirField, BlackBoxFunc}, FieldElement, + acir::{AcirField, BlackBoxFunc}, }; use bn254_blackbox_solver::derive_generators; use iter_extended::vecmap; @@ -610,7 +610,9 @@ fn simplify_black_box_func( "ICE: `BlackBoxFunc::RANGE` calls should be transformed into a `Instruction::Cast`" ) } - BlackBoxFunc::Sha256Compression => SimplifyResult::None, //TODO(Guillaume) + BlackBoxFunc::Sha256Compression => { + blackbox::simplify_sha256_compression(dfg, arguments, block, call_stack) + } BlackBoxFunc::AES128Encrypt => SimplifyResult::None, } } @@ -742,7 +744,7 @@ fn simplify_derive_generators( #[cfg(test)] mod tests { - use crate::ssa::{opt::assert_normalized_ssa_equals, Ssa}; + use crate::ssa::{Ssa, opt::assert_normalized_ssa_equals}; #[test] fn simplify_derive_generators_has_correct_type() { diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs index fac2e8b4d5a..e2aabc62fa6 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs @@ -1,6 +1,7 @@ use std::sync::Arc; -use acvm::{acir::AcirField, BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; +use acvm::blackbox_solver::sha256_compression; +use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement, acir::AcirField}; use crate::ssa::ir::call_stack::CallStackId; use crate::ssa::ir::instruction::BlackBoxFunc; @@ -233,6 +234,55 @@ pub(super) fn simplify_poseidon2_permutation( } } +pub(super) fn simplify_sha256_compression( + dfg: &mut DataFlowGraph, + arguments: &[ValueId], + block: BasicBlockId, + call_stack: CallStackId, +) -> SimplifyResult { + match (dfg.get_array_constant(arguments[0]), dfg.get_array_constant(arguments[1])) { + (Some((state, _)), Some((msg_blocks, _))) + if array_is_constant(dfg, &state) && array_is_constant(dfg, &msg_blocks) => + { + let state: Option> = state + .iter() + .map(|id| { + dfg.get_numeric_constant(*id) + .expect("value id from array should point at constant") + .try_to_u32() + }) + .collect(); + + let Some(mut state) = state.and_then(|vec| <[u32; 8]>::try_from(vec).ok()) else { + return SimplifyResult::None; + }; + + let msg_blocks: Option> = msg_blocks + .iter() + .map(|id| { + dfg.get_numeric_constant(*id) + .expect("value id from array should point at constant") + .try_to_u32() + }) + .collect(); + + let Some(msg_blocks) = msg_blocks.and_then(|vec| <[u32; 16]>::try_from(vec).ok()) + else { + return SimplifyResult::None; + }; + + sha256_compression(&mut state, &msg_blocks); + + let new_state = state.into_iter().map(FieldElement::from); + let typ = NumericType::Unsigned { bit_size: 32 }; + let result_array = make_constant_array(dfg, new_state, typ, block, call_stack); + + SimplifyResult::SimplifiedTo(result_array) + } + _ => SimplifyResult::None, + } +} + pub(super) fn simplify_hash( dfg: &mut DataFlowGraph, arguments: &[ValueId], @@ -308,9 +358,9 @@ pub(super) fn simplify_signature( #[cfg(feature = "bn254")] #[cfg(test)] -mod test { - use crate::ssa::opt::assert_normalized_ssa_equals; +mod multi_scalar_mul { use crate::ssa::Ssa; + use crate::ssa::opt::assert_normalized_ssa_equals; #[cfg(feature = "bn254")] #[test] @@ -395,3 +445,32 @@ mod test { assert_normalized_ssa_equals(ssa, expected_src); } } + +#[cfg(test)] +mod sha256_compression { + use crate::ssa::Ssa; + use crate::ssa::opt::assert_normalized_ssa_equals; + + #[test] + fn is_optimized_out_with_constant_arguments() { + let src = r#" + acir(inline) fn main f0 { + b0(): + v0 = make_array [u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0] : [u32; 8] + v1 = make_array [u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0] : [u32; 16] + v2 = call sha256_compression(v0, v1) -> [u32; 8] + return v2 + }"#; + let ssa = Ssa::from_str_simplifying(src).unwrap(); + let expected_src = r#" + acir(inline) fn main f0 { + b0(): + v1 = make_array [u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0] : [u32; 8] + v2 = make_array [u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0, u32 0] : [u32; 16] + v11 = make_array [u32 2091193876, u32 1113340840, u32 3461668143, u32 3254913767, u32 3068490961, u32 2551409935, u32 2927503052, u32 3205228454] : [u32; 8] + return v11 + } + "#; + assert_normalized_ssa_equals(ssa, expected_src); + } +} diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs index ee2ab43aa5d..189fd20ca53 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs @@ -1,4 +1,4 @@ -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use num_bigint::BigUint; use super::{DataFlowGraph, Instruction, NumericType, SimplifyResult, Type, Value, ValueId}; diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs index ddabdbfa518..48587cb4b7b 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs @@ -1,4 +1,4 @@ -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use crate::ssa::ir::types::NumericType; diff --git a/compiler/noirc_evaluator/src/ssa/ir/printer.rs b/compiler/noirc_evaluator/src/ssa/ir/printer.rs index 06f2ecd70ea..0fac2242abd 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/printer.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/printer.rs @@ -6,8 +6,8 @@ use im::Vector; use iter_extended::vecmap; use crate::ssa::{ - ir::types::{NumericType, Type}, Ssa, + ir::types::{NumericType, Type}, }; use super::{ @@ -344,11 +344,7 @@ pub(crate) fn try_to_extract_string_from_error_payload( values: &[ValueId], dfg: &DataFlowGraph, ) -> Option { - if is_string_type && values.len() == 1 { - dfg.get_string(values[0]) - } else { - None - } + if is_string_type && values.len() == 1 { dfg.get_string(values[0]) } else { None } } fn display_constrain_error( diff --git a/compiler/noirc_evaluator/src/ssa/ir/types.rs b/compiler/noirc_evaluator/src/ssa/ir/types.rs index ecf103434a2..ca6242d51c2 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -2,7 +2,7 @@ use noirc_frontend::signed_field::SignedField; use serde::{Deserialize, Serialize}; use std::sync::Arc; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use iter_extended::vecmap; use crate::ssa::ssa_gen::SSA_WORD_SIZE; @@ -66,11 +66,7 @@ impl NumericType { if value.is_negative { return Some(format!("0..={}", max)); } - if value.field <= max.into() { - None - } else { - Some(format!("0..={}", max)) - } + if value.field <= max.into() { None } else { Some(format!("0..={}", max)) } } NumericType::Signed { bit_size } => { let min = 2u128.pow(bit_size - 1); diff --git a/compiler/noirc_evaluator/src/ssa/opt/array_set.rs b/compiler/noirc_evaluator/src/ssa/opt/array_set.rs index ec648131547..7bef8e7b1ae 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/array_set.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/array_set.rs @@ -191,7 +191,7 @@ fn make_mutable( #[cfg(test)] mod tests { - use crate::ssa::{opt::assert_normalized_ssa_equals, Ssa}; + use crate::ssa::{Ssa, opt::assert_normalized_ssa_equals}; #[test] fn array_set_in_loop_with_conditional_clone() { diff --git a/compiler/noirc_evaluator/src/ssa/opt/basic_conditional.rs b/compiler/noirc_evaluator/src/ssa/opt/basic_conditional.rs new file mode 100644 index 00000000000..cbc36787a25 --- /dev/null +++ b/compiler/noirc_evaluator/src/ssa/opt/basic_conditional.rs @@ -0,0 +1,526 @@ +use std::collections::HashSet; + +use acvm::AcirField; +use fxhash::FxHashMap as HashMap; +use iter_extended::vecmap; + +use crate::ssa::{ + Ssa, + ir::{ + basic_block::BasicBlockId, + cfg::ControlFlowGraph, + dfg::DataFlowGraph, + function::{Function, FunctionId}, + function_inserter::FunctionInserter, + instruction::{BinaryOp, Instruction, TerminatorInstruction}, + post_order::PostOrder, + value::ValueId, + }, +}; + +use super::flatten_cfg::Context; +#[derive(Debug, Clone)] +struct BasicConditional { + block_entry: BasicBlockId, + block_then: Option, + block_else: Option, + block_exit: BasicBlockId, +} + +impl Ssa { + #[tracing::instrument(level = "trace", skip(self))] + /// This pass flatten simple IF-THEN-ELSE statements + /// This optimization pass identifies simple conditional control flow patterns in unconstrained code + /// and flattens them to reduce the number of basic blocks and improve performance. + /// + /// e.g: if c {a} else {b} would be flattened to c*(a-b)+b + /// A simple conditional pattern is defined as an IF-THEN (with optional ELSE) statement, with no nested conditional nor loop statements + /// Performance improvement is based on a simple execution cost metric + pub(crate) fn flatten_basic_conditionals(mut self) -> Ssa { + // Retrieve the 'no_predicates' attribute of the functions in a map, to avoid problems with borrowing + let mut no_predicates = HashMap::default(); + for function in self.functions.values() { + no_predicates.insert(function.id(), function.is_no_predicates()); + } + for function in self.functions.values_mut() { + flatten_function(function, &mut no_predicates); + } + self + } +} + +/// Returns the blocks of the simple conditional sub-graph whose input block is the entry. +/// Returns None if the input block is not the entry block of a simple conditional. +fn is_conditional( + block: BasicBlockId, + cfg: &ControlFlowGraph, + function: &Function, +) -> Option { + // jump overhead is the cost for doing the conditional and jump around the blocks + // We use 10 as a rough estimate, the real cost is less. + let jump_overhead = 10; + let mut successors = cfg.successors(block); + let mut result = None; + // a conditional must have 2 branches + if successors.len() != 2 { + return None; + } + let left = successors.next().unwrap(); + let right = successors.next().unwrap(); + let mut left_successors = cfg.successors(left); + let mut right_successors = cfg.successors(right); + let left_successors_len = left_successors.len(); + let right_successors_len = right_successors.len(); + let next_left = left_successors.next(); + let next_right = right_successors.next(); + if next_left == Some(block) || next_right == Some(block) { + // this is a loop, not a conditional + return None; + } + if left_successors_len == 1 && right_successors_len == 1 && next_left == next_right { + // The branches join on one block so it is a non-nested conditional + let cost_left = block_cost(left, &function.dfg); + let cost_right = block_cost(right, &function.dfg); + // For the flattening to be valuable, we compare the cost of the flattened code with the average cost of the 2 branches, + // including an overhead to take into account the jumps between the blocks. + let cost = cost_right.saturating_add(cost_left); + if cost < cost / 2 + jump_overhead { + if let Some(TerminatorInstruction::JmpIf { + condition: _, + then_destination, + else_destination, + call_stack: _, + }) = function.dfg[block].terminator() + { + result = Some(BasicConditional { + block_entry: block, + block_then: Some(*then_destination), + block_else: Some(*else_destination), + block_exit: next_left.unwrap(), + }); + } + } + } else if left_successors_len == 1 && next_left == Some(right) { + // Left branch joins the right branch, e.g if/then statement with no else + // This case may not happen (i.e not generated), but it is safer to handle it (e.g in case it happens due to some optimizations) + let cost = block_cost(left, &function.dfg); + if cost < cost / 2 + jump_overhead { + if let Some(TerminatorInstruction::JmpIf { + condition: _, + then_destination, + else_destination, + call_stack: _, + }) = function.dfg[block].terminator() + { + let (block_then, block_else) = if left == *then_destination { + (Some(left), None) + } else if left == *else_destination { + (None, Some(left)) + } else { + return None; + }; + + result = Some(BasicConditional { + block_entry: block, + block_then, + block_else, + block_exit: right, + }); + } + } + } else if right_successors_len == 1 && next_right == Some(left) { + // Right branch joins the left branch, e.g if/else statement with no then + // This case may not happen (i.e not generated), but it is safer to handle it (e.g in case it happens due to some optimizations) + let cost = block_cost(right, &function.dfg); + if cost < cost / 2 + jump_overhead { + if let Some(TerminatorInstruction::JmpIf { + condition: _, + then_destination, + else_destination, + call_stack: _, + }) = function.dfg[block].terminator() + { + let (block_then, block_else) = if right == *then_destination { + (Some(right), None) + } else if right == *else_destination { + (None, Some(right)) + } else { + return None; + }; + result = Some(BasicConditional { + block_entry: block, + block_then, + block_else, + block_exit: right, + }); + } + } + } + // A conditional exit would have exactly 2 predecessors + result.filter(|result| cfg.predecessors(result.block_exit).len() == 2) +} + +/// Computes a cost estimate of a basic block +/// returns u32::MAX if the block has side-effect instructions +/// WARNING: these are estimates of the runtime cost of each instruction, +/// 1 being the cost of the simplest instruction. These numbers can be improved. +fn block_cost(block: BasicBlockId, dfg: &DataFlowGraph) -> u32 { + let mut cost: u32 = 0; + for instruction in dfg[block].instructions() { + let instruction_cost = match &dfg[*instruction] { + Instruction::Binary(binary) => { + match binary.operator { + BinaryOp::Add { unchecked } + | BinaryOp::Sub { unchecked } + | BinaryOp::Mul { unchecked } => if unchecked { 3 } else { return u32::MAX }, + BinaryOp::Div + | BinaryOp::Mod => return u32::MAX, + BinaryOp::Eq => 1, + BinaryOp::Lt => 5, + BinaryOp::And + | BinaryOp::Or + | BinaryOp::Xor => 1, + BinaryOp::Shl + | BinaryOp::Shr => return u32::MAX, + } + }, + // A Cast can be either simplified, or lead to a truncate + Instruction::Cast(_, _) => 3, + Instruction::Not(_) => 1, + Instruction::Truncate { .. } => 7, + + Instruction::Constrain(_,_,_) + | Instruction::ConstrainNotEqual(_,_,_) + | Instruction::RangeCheck { .. } + // Calls with no-predicate set to true could be supported, but + // they are likely to be too costly anyways. Simple calls would + // have been inlined already. + | Instruction::Call { .. } + | Instruction::Load { .. } + | Instruction::Store { .. } + | Instruction::ArraySet { .. } => return u32::MAX, + + Instruction::ArrayGet { array, index } => { + // A get can fail because of out-of-bound index + let mut in_bound = false; + // check if index is in bound + if let (Some(index), Some(len)) = (dfg.get_numeric_constant(*index), dfg.try_get_array_length(*array)) { + // The index is in-bounds + if index.to_u128() < len as u128 { + in_bound = true; + } + } + if !in_bound { + return u32::MAX; + } + 1 + }, + // if less than 10 elements, it is translated into a store for each element + // if more than 10, it is a loop, so 20 should be a good estimate, worst case being 10 stores and ~10 index increments + Instruction::MakeArray { .. } => 20, + + Instruction::Allocate + | Instruction::EnableSideEffectsIf { .. } + | Instruction::IncrementRc { .. } + | Instruction::DecrementRc { .. } + | Instruction::Noop => 0, + Instruction::IfElse { .. } => 1, + }; + cost += instruction_cost; + } + cost +} + +/// Identifies all simple conditionals in the function and flattens them +fn flatten_function(function: &mut Function, no_predicates: &mut HashMap) { + // This pass is dedicated to brillig functions + if !function.runtime().is_brillig() { + return; + } + let cfg = ControlFlowGraph::with_function(function); + let mut stack = vec![function.entry_block()]; + let mut processed = HashSet::new(); + let mut conditionals = Vec::new(); + + // 1. Process all blocks of the cfg, starting from the root and following the successors + while let Some(block) = stack.pop() { + // Avoid cycles + if processed.contains(&block) { + continue; + } + processed.insert(block); + + // Identify the simple conditionals + if let Some(conditional) = is_conditional(block, &cfg, function) { + // no need to check the branches, process the join block directly + stack.push(conditional.block_exit); + conditionals.push(conditional); + } else { + stack.extend(cfg.successors(block)); + } + } + + // 2. Flatten all simple conditionals + // process basic conditionals in reverse order so that + // a conditional does not impact the previous ones + conditionals.reverse(); + flatten_multiple(&conditionals, function, no_predicates); +} + +fn flatten_multiple( + conditionals: &Vec, + function: &mut Function, + no_predicates: &mut HashMap, +) { + // 1. process each basic conditional, using a new context per conditional + let post_order = PostOrder::with_function(function); + + let mut mapping = HashMap::default(); + for conditional in conditionals { + let cfg = ControlFlowGraph::with_function(function); + let cfg_root = function.entry_block(); + let mut branch_ends = HashMap::default(); + branch_ends.insert(conditional.block_entry, conditional.block_exit); + let mut context = Context::new(function, cfg, branch_ends, cfg_root); + context.flatten_single_conditional(conditional, no_predicates); + // extract the mapping into 'mapping + context.inserter.extract_mapping(&mut mapping); + } + // 2. re-map the full program for values that may been simplified. + if !mapping.is_empty() { + for block in post_order.as_slice() { + Context::map_block_with_mapping(mapping.clone(), function, *block); + } + } +} + +impl Context<'_> { + fn flatten_single_conditional( + &mut self, + conditional: &BasicConditional, + no_predicates: &mut HashMap, + ) { + // Manually inline 'then', 'else' and 'exit' into the entry block + //0. initialize the context for flattening a 'single conditional' + let old_target = self.target_block; + let old_no_predicate = self.no_predicate; + let mut queue = vec![]; + self.target_block = conditional.block_entry; + self.no_predicate = true; + //1. process 'then' branch + self.inline_block(conditional.block_entry, no_predicates); + let to_process = self.handle_terminator(conditional.block_entry, &queue); + queue.extend(to_process); + if let Some(then) = conditional.block_then { + assert_eq!(queue.pop(), conditional.block_then); + self.inline_block(then, no_predicates); + let to_process = self.handle_terminator(then, &queue); + + for incoming_block in to_process { + if !queue.contains(&incoming_block) { + queue.push(incoming_block); + } + } + } + + //2. process 'else' branch, in case there is no 'then' + let next = queue.pop(); + if next == conditional.block_else { + let next = next.unwrap(); + self.inline_block(next, no_predicates); + let _ = self.handle_terminator(next, &queue); + } else { + assert_eq!(next, Some(conditional.block_exit)); + } + + //3. process 'exit' block + self.inline_block(conditional.block_exit, no_predicates); + // Manually set the terminator of the entry block to the one of the exit block + let terminator = + self.inserter.function.dfg[conditional.block_exit].terminator().unwrap().clone(); + let new_terminator = match terminator { + TerminatorInstruction::JmpIf { + condition, + then_destination, + else_destination, + call_stack, + } => { + let condition = self.inserter.resolve(condition); + TerminatorInstruction::JmpIf { + condition, + then_destination, + else_destination, + call_stack, + } + } + TerminatorInstruction::Jmp { destination, arguments, call_stack } => { + let arguments = vecmap(arguments, |value| self.inserter.resolve(value)); + TerminatorInstruction::Jmp { destination, arguments, call_stack } + } + TerminatorInstruction::Return { return_values, call_stack } => { + let return_values = vecmap(return_values, |value| self.inserter.resolve(value)); + TerminatorInstruction::Return { return_values, call_stack } + } + }; + self.inserter.function.dfg.set_block_terminator(conditional.block_entry, new_terminator); + self.inserter.map_data_bus_in_place(); + //4. restore the context, in case it is re-used. + self.target_block = old_target; + self.no_predicate = old_no_predicate; + } + + fn map_block_with_mapping( + mapping: HashMap, + func: &mut Function, + block: BasicBlockId, + ) { + // Map all instructions in the block + let mut inserter = FunctionInserter::new(func); + inserter.set_mapping(mapping); + let instructions = inserter.function.dfg[block].instructions().to_vec(); + for instruction in instructions { + inserter.map_instruction_in_place(instruction); + } + inserter.map_terminator_in_place(block); + } +} + +#[cfg(test)] +mod test { + use crate::ssa::{Ssa, opt::assert_normalized_ssa_equals}; + + #[test] + fn basic_jmpif() { + let src = " + brillig(inline) fn foo f0 { + b0(v0: u32): + v3 = eq v0, u32 0 + jmpif v3 then: b2, else: b1 + b1(): + jmp b3(u32 5) + b2(): + jmp b3(u32 3) + b3(v1: u32): + return v1 + } + "; + let ssa = Ssa::from_str(src).unwrap(); + assert_eq!(ssa.main().reachable_blocks().len(), 4); + + let expected = " + brillig(inline) fn foo f0 { + b0(v0: u32): + v2 = eq v0, u32 0 + v3 = not v2 + v4 = cast v2 as u32 + v5 = cast v3 as u32 + v7 = unchecked_mul v4, u32 3 + v9 = unchecked_mul v5, u32 5 + v10 = unchecked_add v7, v9 + return v10 + } + "; + + let ssa = ssa.flatten_basic_conditionals(); + assert_normalized_ssa_equals(ssa, expected); + } + + #[test] + fn array_jmpif() { + let src = r#" + brillig(inline) fn foo f0 { + b0(v0: u32): + v3 = eq v0, u32 5 + jmpif v3 then: b2, else: b1 + b1(): + v6 = make_array b"foo" + jmp b3(v6) + b2(): + v10 = make_array b"bar" + jmp b3(v10) + b3(v1: [u8; 3]): + return v1 + } + "#; + let ssa = Ssa::from_str(src).unwrap(); + assert_eq!(ssa.main().reachable_blocks().len(), 4); + let ssa = ssa.flatten_basic_conditionals(); + // make_array is not simplified + assert_normalized_ssa_equals(ssa, src); + } + + #[test] + fn nested_jmpifs() { + let src = " + brillig(inline) fn foo f0 { + b0(v0: u32): + v5 = eq v0, u32 5 + v6 = not v5 + jmpif v5 then: b5, else: b1 + b1(): + v8 = lt v0, u32 3 + jmpif v8 then: b3, else: b2 + b2(): + v9 = truncate v0 to 2 bits, max_bit_size: 32 + jmp b4(v9) + b3(): + v10 = truncate v0 to 1 bits, max_bit_size: 32 + jmp b4(v10) + b4(v1: u32): + jmp b9(v1) + b5(): + v12 = lt u32 2, v0 + jmpif v12 then: b7, else: b6 + b6(): + v13 = truncate v0 to 3 bits, max_bit_size: 32 + jmp b8(v13) + b7(): + v14 = and v0, u32 2 + jmp b8(v14) + b8(v2: u32): + jmp b9(v2) + b9(v3: u32): + return v3 + } + "; + let ssa = Ssa::from_str(src).unwrap(); + assert_eq!(ssa.main().reachable_blocks().len(), 10); + + let expected = " + brillig(inline) fn foo f0 { + b0(v0: u32): + v3 = eq v0, u32 5 + v4 = not v3 + jmpif v3 then: b2, else: b1 + b1(): + v6 = lt v0, u32 3 + v7 = truncate v0 to 1 bits, max_bit_size: 32 + v8 = not v6 + v9 = truncate v0 to 2 bits, max_bit_size: 32 + v10 = cast v6 as u32 + v11 = cast v8 as u32 + v12 = unchecked_mul v10, v7 + v13 = unchecked_mul v11, v9 + v14 = unchecked_add v12, v13 + jmp b3(v14) + b2(): + v16 = lt u32 2, v0 + v17 = and v0, u32 2 + v18 = not v16 + v19 = truncate v0 to 3 bits, max_bit_size: 32 + v20 = cast v16 as u32 + v21 = cast v18 as u32 + v22 = unchecked_mul v20, v17 + v23 = unchecked_mul v21, v19 + v24 = unchecked_add v22, v23 + jmp b3(v24) + b3(v1: u32): + return v1 + } + "; + + let ssa = ssa.flatten_basic_conditionals(); + assert_eq!(ssa.main().reachable_blocks().len(), 4); + assert_normalized_ssa_equals(ssa, expected); + } +} diff --git a/compiler/noirc_evaluator/src/ssa/opt/brillig_array_gets.rs b/compiler/noirc_evaluator/src/ssa/opt/brillig_array_gets.rs index 2c11d36fbdf..c5d485dd161 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/brillig_array_gets.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/brillig_array_gets.rs @@ -15,12 +15,12 @@ use fxhash::FxHashMap as HashMap; use crate::{ brillig::brillig_ir::BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, ssa::{ + Ssa, ir::{ function::Function, instruction::Instruction, types::{NumericType, Type}, }, - Ssa, }, }; diff --git a/compiler/noirc_evaluator/src/ssa/opt/brillig_entry_points.rs b/compiler/noirc_evaluator/src/ssa/opt/brillig_entry_points.rs index e03f14b2721..380daabee6c 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/brillig_entry_points.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/brillig_entry_points.rs @@ -64,12 +64,12 @@ use std::collections::{BTreeMap, BTreeSet}; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::ssa::{ + Ssa, ir::{ function::{Function, FunctionId}, instruction::Instruction, value::Value, }, - Ssa, }; use super::inlining::called_functions_vec; diff --git a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs index 2e440985cc2..3bde1d7530f 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -22,9 +22,9 @@ use std::collections::{BTreeMap, HashSet, VecDeque}; use acvm::{ - acir::AcirField, - brillig_vm::{MemoryValue, VMStatus, VM}, FieldElement, + acir::AcirField, + brillig_vm::{MemoryValue, VM, VMStatus}, }; use bn254_blackbox_solver::Bn254BlackBoxSolver; use im::Vector; @@ -32,9 +32,9 @@ use iter_extended::vecmap; use crate::{ brillig::{ + Brillig, BrilligOptions, brillig_gen::gen_brillig_for, brillig_ir::{artifact::BrilligParameter, brillig_variable::get_bit_size_from_ssa_type}, - Brillig, BrilligOptions, }, ssa::{ ir::{ @@ -813,6 +813,7 @@ mod test { use crate::{ brillig::BrilligOptions, ssa::{ + Ssa, function_builder::FunctionBuilder, ir::{ function::RuntimeType, @@ -820,7 +821,6 @@ mod test { types::{NumericType, Type}, }, opt::assert_normalized_ssa_equals, - Ssa, }, }; diff --git a/compiler/noirc_evaluator/src/ssa/opt/die.rs b/compiler/noirc_evaluator/src/ssa/opt/die.rs index c45e1886269..e742ad4aa5d 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/die.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/die.rs @@ -17,7 +17,7 @@ use crate::ssa::{ ssa_gen::Ssa, }; -use super::rc::{pop_rc_for, RcInstruction}; +use super::rc::{RcInstruction, pop_rc_for}; impl Ssa { /// Performs Dead Instruction Elimination (DIE) to remove any instructions with @@ -41,11 +41,7 @@ impl Ssa { .par_iter_mut() .filter_map(|(id, func)| { let set = func.dead_instruction_elimination(true, flattened, skip_brillig); - if func.runtime().is_brillig() { - Some((*id, set)) - } else { - None - } + if func.runtime().is_brillig() { Some((*id, set)) } else { None } }) .collect(); @@ -139,9 +135,8 @@ struct Context { /// them just yet. flattened: bool, - // When tracking mutations we consider arrays with the same type as all being possibly mutated. - // This we consider to span all blocks of the functions. - mutated_array_types: HashSet, + /// Track IncrementRc instructions per block to determine whether they are useless. + rc_tracker: RcTracker, } impl Context { @@ -171,10 +166,8 @@ impl Context { let block = &function.dfg[block_id]; self.mark_terminator_values_as_used(function, block); - // Lend the shared array type to the tracker. - let mut mutated_array_types = std::mem::take(&mut self.mutated_array_types); - let mut rc_tracker = RcTracker::new(&mut mutated_array_types); - rc_tracker.mark_terminator_arrays_as_used(function, block); + self.rc_tracker.new_block(); + self.rc_tracker.mark_terminator_arrays_as_used(function, block); let instructions_len = block.instructions().len(); @@ -207,12 +200,11 @@ impl Context { } } - rc_tracker.track_inc_rcs_to_remove(*instruction_id, function); + self.rc_tracker.track_inc_rcs_to_remove(*instruction_id, function); } - self.instructions_to_remove.extend(rc_tracker.get_non_mutated_arrays(&function.dfg)); - self.instructions_to_remove.extend(rc_tracker.rc_pairs_to_remove); - + self.instructions_to_remove.extend(self.rc_tracker.get_non_mutated_arrays(&function.dfg)); + self.instructions_to_remove.extend(self.rc_tracker.rc_pairs_to_remove.drain()); // If there are some instructions that might trigger an out of bounds error, // first add constrain checks. Then run the DIE pass again, which will remove those // but leave the constrains (any any value needed by those constrains) @@ -232,9 +224,6 @@ impl Context { .instructions_mut() .retain(|instruction| !self.instructions_to_remove.contains(instruction)); - // Take the mutated array back. - self.mutated_array_types = mutated_array_types; - false } @@ -283,11 +272,15 @@ impl Context { let typ = typ.get_contained_array(); // Want to store the array type which is being referenced, // because it's the underlying array that the `inc_rc` is associated with. - self.mutated_array_types.insert(typ.clone()); + self.add_mutated_array_type(typ.clone()); } } } + fn add_mutated_array_type(&mut self, typ: Type) { + self.rc_tracker.mutated_array_types.insert(typ.get_contained_array().clone()); + } + /// Go through the RC instructions collected when we figured out which values were unused; /// for each RC that refers to an unused value, remove the RC as well. fn remove_rc_instructions(&self, dfg: &mut DataFlowGraph) { @@ -619,8 +612,9 @@ fn apply_side_effects( (lhs, rhs) } +#[derive(Default)] /// Per block RC tracker. -struct RcTracker<'a> { +struct RcTracker { // We can track IncrementRc instructions per block to determine whether they are useless. // IncrementRc and DecrementRc instructions are normally side effectual instructions, but we remove // them if their value is not used anywhere in the function. However, even when their value is used, their existence @@ -635,7 +629,8 @@ struct RcTracker<'a> { // If an array is the same type as one of those non-mutated array types, we can safely remove all IncrementRc instructions on that array. inc_rcs: HashMap>, // Mutated arrays shared across the blocks of the function. - mutated_array_types: &'a mut HashSet, + // When tracking mutations we consider arrays with the same type as all being possibly mutated. + mutated_array_types: HashSet, // The SSA often creates patterns where after simplifications we end up with repeat // IncrementRc instructions on the same value. We track whether the previous instruction was an IncrementRc, // and if the current instruction is also an IncrementRc on the same value we remove the current instruction. @@ -643,15 +638,12 @@ struct RcTracker<'a> { previous_inc_rc: Option, } -impl<'a> RcTracker<'a> { - fn new(mutated_array_types: &'a mut HashSet) -> Self { - Self { - rcs_with_possible_pairs: Default::default(), - rc_pairs_to_remove: Default::default(), - inc_rcs: Default::default(), - previous_inc_rc: Default::default(), - mutated_array_types, - } +impl RcTracker { + fn new_block(&mut self) { + self.rcs_with_possible_pairs.clear(); + self.rc_pairs_to_remove.clear(); + self.inc_rcs.clear(); + self.previous_inc_rc = Default::default(); } fn mark_terminator_arrays_as_used(&mut self, function: &Function, block: &BasicBlock) { @@ -762,6 +754,7 @@ mod test { use noirc_frontend::monomorphization::ast::InlineType; use crate::ssa::{ + Ssa, function_builder::FunctionBuilder, ir::{ function::RuntimeType, @@ -769,7 +762,6 @@ mod test { types::{NumericType, Type}, }, opt::assert_normalized_ssa_equals, - Ssa, }; #[test] @@ -1132,4 +1124,38 @@ mod test { "; assert_normalized_ssa_equals(ssa, expected); } + + #[test] + fn do_not_remove_inc_rc_if_mutated_in_other_block() { + let src = " + brillig(inline) fn main f0 { + b0(v0: &mut [Field; 3]): + v1 = load v0 -> [Field; 3] + inc_rc v1 + jmp b1() + b1(): + v2 = load v0 -> [Field; 3] + v3 = array_set v2, index u32 0, value u32 0 + store v3 at v0 + return + } + "; + let ssa = Ssa::from_str(src).unwrap(); + + let expected = " + brillig(inline) fn main f0 { + b0(v0: &mut [Field; 3]): + v1 = load v0 -> [Field; 3] + inc_rc v1 + jmp b1() + b1(): + v2 = load v0 -> [Field; 3] + v4 = array_set v2, index u32 0, value u32 0 + store v4 at v0 + return + } + "; + let ssa = ssa.dead_instruction_elimination(); + assert_normalized_ssa_equals(ssa, expected); + } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 1a9f4b6b622..a25e3db2b08 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -133,7 +133,7 @@ //! store v12 at v5 (new store) use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; -use acvm::{acir::AcirField, acir::BlackBoxFunc, FieldElement}; +use acvm::{FieldElement, acir::AcirField, acir::BlackBoxFunc}; use iter_extended::vecmap; use crate::ssa::{ @@ -176,12 +176,15 @@ impl Ssa { } } -struct Context<'f> { - inserter: FunctionInserter<'f>, +pub(crate) struct Context<'f> { + pub(crate) inserter: FunctionInserter<'f>, /// This ControlFlowGraph is the graph from before the function was modified by this flattening pass. cfg: ControlFlowGraph, + /// Target block of the flattening + pub(crate) target_block: BasicBlockId, + /// Maps start of branch -> end of branch branch_ends: HashMap, @@ -213,6 +216,10 @@ struct Context<'f> { /// us from unnecessarily inserting extra instructions, and keeps ids unique which /// helps simplifications. not_instructions: HashMap, + + /// Flag to tell the context to not issue 'enable_side_effect' instructions during flattening. + /// This should be set to true only by flatten_single(), when no instruction is known to fail. + pub(crate) no_predicate: bool, } #[derive(Clone)] @@ -249,6 +256,7 @@ fn flatten_function_cfg(function: &mut Function, no_predicates: &HashMap { - fn flatten(&mut self, no_predicates: &HashMap) { +impl<'f> Context<'f> { + //impl Context<'_> { + pub(crate) fn new( + function: &'f mut Function, + cfg: ControlFlowGraph, + branch_ends: HashMap, + target_block: BasicBlockId, + ) -> Self { + Context { + inserter: FunctionInserter::new(function), + cfg, + branch_ends, + condition_stack: Vec::new(), + arguments_stack: Vec::new(), + local_allocations: HashSet::default(), + not_instructions: HashMap::default(), + target_block, + no_predicate: false, + } + } + + pub(crate) fn flatten(&mut self, no_predicates: &HashMap) { // Flatten the CFG by inlining all instructions from the queued blocks // until all blocks have been flattened. // We follow the terminator of each block to determine which blocks to // process next - let mut queue = vec![self.inserter.function.entry_block()]; + let mut queue = vec![self.target_block]; while let Some(block) = queue.pop() { self.inline_block(block, no_predicates); let to_process = self.handle_terminator(block, &queue); @@ -318,10 +348,14 @@ impl Context<'_> { result } - // Inline all instructions from the given block into the entry block, and track slice capacities - fn inline_block(&mut self, block: BasicBlockId, no_predicates: &HashMap) { - if self.inserter.function.entry_block() == block { - // we do not inline the entry block into itself + // Inline all instructions from the given block into the target block, and track slice capacities + pub(crate) fn inline_block( + &mut self, + block: BasicBlockId, + no_predicates: &HashMap, + ) { + if self.target_block == block { + // we do not inline the target block into itself // for the outer block before we start inlining return; } @@ -354,7 +388,7 @@ impl Context<'_> { /// For a normal block, it would be its successor /// For blocks related to a conditional statement, we ensure to process /// the 'then-branch', then the 'else-branch' (if it exists), and finally the end block - fn handle_terminator( + pub(crate) fn handle_terminator( &mut self, block: BasicBlockId, work_list: &[BasicBlockId], @@ -388,9 +422,9 @@ impl Context<'_> { let return_values = vecmap(return_values.clone(), |value| self.inserter.resolve(value)); let new_return = TerminatorInstruction::Return { return_values, call_stack }; - let entry = self.inserter.function.entry_block(); + let target = self.target_block; - self.inserter.function.dfg.set_block_terminator(entry, new_return); + self.inserter.function.dfg.set_block_terminator(target, new_return); vec![] } } @@ -544,7 +578,7 @@ impl Context<'_> { } else { self.inserter.function.dfg.make_constant(FieldElement::zero(), NumericType::bool()) }; - let block = self.inserter.function.entry_block(); + let block = self.target_block; // Cannot include this in the previous vecmap since it requires exclusive access to self let args = vecmap(args, |(then_arg, else_arg)| { @@ -568,11 +602,11 @@ impl Context<'_> { destination } - /// Insert a new instruction into the function's entry block. + /// Insert a new instruction into the target block. /// Unlike push_instruction, this function will not map any ValueIds. /// within the given instruction, nor will it modify self.values in any way. fn insert_instruction(&mut self, instruction: Instruction, call_stack: CallStackId) -> ValueId { - let block = self.inserter.function.entry_block(); + let block = self.target_block; self.inserter .function .dfg @@ -580,7 +614,7 @@ impl Context<'_> { .first() } - /// Inserts a new instruction into the function's entry block, using the given + /// Inserts a new instruction into the target block, using the given /// control type variables to specify result types if needed. /// Unlike push_instruction, this function will not map any ValueIds. /// within the given instruction, nor will it modify self.values in any way. @@ -590,7 +624,7 @@ impl Context<'_> { ctrl_typevars: Option>, call_stack: CallStackId, ) -> InsertInstructionResult { - let block = self.inserter.function.entry_block(); + let block = self.target_block; self.inserter.function.dfg.insert_instruction_and_results( instruction, block, @@ -600,11 +634,14 @@ impl Context<'_> { } /// Checks the branch condition on the top of the stack and uses it to build and insert an - /// `EnableSideEffectsIf` instruction into the entry block. + /// `EnableSideEffectsIf` instruction into the target block. /// /// If the stack is empty, a "true" u1 constant is taken to be the active condition. This is /// necessary for re-enabling side-effects when re-emerging to a branch depth of 0. fn insert_current_side_effects_enabled(&mut self) { + if self.no_predicate { + return; + } let condition = match self.get_last_condition() { Some(cond) => cond, None => { @@ -616,7 +653,7 @@ impl Context<'_> { self.insert_instruction_with_typevars(enable_side_effects, None, call_stack); } - /// Push the given instruction to the end of the entry block of the current function. + /// Push the given instruction to the end of the target block of the current function. /// /// Note that each ValueId of the instruction will be mapped via self.inserter.resolve. /// As a result, the instruction that will be pushed will actually be a new instruction @@ -631,8 +668,8 @@ impl Context<'_> { let instruction = self.handle_instruction_side_effects(instruction, call_stack); let instruction_is_allocate = matches!(&instruction, Instruction::Allocate); - let entry = self.inserter.function.entry_block(); - let results = self.inserter.push_instruction_value(instruction, id, entry, call_stack); + let results = + self.inserter.push_instruction_value(instruction, id, self.target_block, call_stack); // Remember an allocate was created local to this branch so that we do not try to merge store // values across branches for it later. @@ -816,13 +853,13 @@ mod test { use acvm::acir::AcirField; use crate::ssa::{ + Ssa, ir::{ dfg::DataFlowGraph, instruction::{Instruction, TerminatorInstruction}, value::{Value, ValueId}, }, opt::assert_normalized_ssa_equals, - Ssa, }; #[test] diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index f4638cf85e4..6e8c7df2bba 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -1,4 +1,4 @@ -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use fxhash::{FxHashMap as HashMap, FxHashSet}; use crate::ssa::ir::{ diff --git a/compiler/noirc_evaluator/src/ssa/opt/hint.rs b/compiler/noirc_evaluator/src/ssa/opt/hint.rs index be088c3da94..911554e5d6d 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/hint.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/hint.rs @@ -6,8 +6,8 @@ mod tests { brillig::BrilligOptions, errors::RuntimeError, ssa::{ - opt::assert_normalized_ssa_equals, optimize_all, Ssa, SsaBuilder, SsaEvaluatorOptions, - SsaLogging, + Ssa, SsaBuilder, SsaEvaluatorOptions, SsaLogging, opt::assert_normalized_ssa_equals, + optimize_all, }, }; @@ -20,7 +20,7 @@ mod tests { emit_ssa: None, skip_underconstrained_check: true, enable_brillig_constraints_check_lookback: false, - enable_brillig_constraints_check: false, + skip_brillig_constraints_check: true, inliner_aggressiveness: 0, max_bytecode_increase_percent: None, }; diff --git a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index ba0c998216c..15414e92eff 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -23,7 +23,7 @@ use crate::ssa::{ pub(super) mod inline_info; -pub(super) use inline_info::{compute_inline_infos, InlineInfo, InlineInfos}; +pub(super) use inline_info::{InlineInfo, InlineInfos, compute_inline_infos}; /// An arbitrary limit to the maximum number of recursive call /// frames at any point in time. @@ -784,10 +784,11 @@ impl<'function> PerFunctionContext<'function> { mod test { use std::cmp::max; - use acvm::{acir::AcirField, FieldElement}; + use acvm::{FieldElement, acir::AcirField}; use noirc_frontend::monomorphization::ast::InlineType; use crate::ssa::{ + Ssa, function_builder::FunctionBuilder, ir::{ basic_block::BasicBlockId, @@ -797,7 +798,6 @@ mod test { types::{NumericType, Type}, }, opt::{assert_normalized_ssa_equals, inlining::inline_info::compute_bottom_up_order}, - Ssa, }; #[test] diff --git a/compiler/noirc_evaluator/src/ssa/opt/inlining/inline_info.rs b/compiler/noirc_evaluator/src/ssa/opt/inlining/inline_info.rs index 26bb2cad675..d40baaae6a3 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/inlining/inline_info.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/inlining/inline_info.rs @@ -311,11 +311,7 @@ fn mark_functions_to_retain_recursive( let inlined_function_weights: i64 = called_functions.iter().fold(0, |acc, callee| { let info = &inline_infos[callee]; // If the callee is not going to be inlined then we can ignore its cost. - if info.should_inline { - acc.saturating_add(info.weight) - } else { - acc - } + if info.should_inline { acc.saturating_add(info.weight) } else { acc } }); let this_function_weight = inlined_function_weights diff --git a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs index 19fc6a7f5a2..f68afc55efa 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs @@ -7,22 +7,22 @@ //! - Already marked as loop invariants //! //! We also check that we are not hoisting instructions with side effects. -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::ssa::{ + Ssa, ir::{ basic_block::BasicBlockId, function::Function, function_inserter::FunctionInserter, instruction::{ - binary::eval_constant_binary_op, Binary, BinaryOp, Instruction, InstructionId, + Binary, BinaryOp, Instruction, InstructionId, binary::eval_constant_binary_op, }, post_order::PostOrder, types::Type, value::ValueId, }, - Ssa, }; use super::unrolling::{Loop, Loops}; @@ -373,8 +373,8 @@ impl<'f> LoopInvariantContext<'f> { #[cfg(test)] mod test { - use crate::ssa::opt::assert_normalized_ssa_equals; use crate::ssa::Ssa; + use crate::ssa::opt::assert_normalized_ssa_equals; #[test] fn simple_loop_invariant_code_motion() { diff --git a/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs b/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs index b4b2dcb2e44..9b58a0de329 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs @@ -668,10 +668,11 @@ impl<'f> PerFunctionContext<'f> { mod tests { use std::sync::Arc; - use acvm::{acir::AcirField, FieldElement}; + use acvm::{FieldElement, acir::AcirField}; use im::vector; use crate::ssa::{ + Ssa, function_builder::FunctionBuilder, ir::{ basic_block::BasicBlockId, @@ -681,7 +682,6 @@ mod tests { types::Type, }, opt::assert_normalized_ssa_equals, - Ssa, }; #[test] diff --git a/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs b/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs index 91e27f07b8e..8c74852b53b 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs @@ -58,11 +58,7 @@ pub(super) enum ReferenceValue { impl ReferenceValue { fn unify(self, other: Self) -> Self { - if self == other { - self - } else { - ReferenceValue::Unknown - } + if self == other { self } else { ReferenceValue::Unknown } } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/compiler/noirc_evaluator/src/ssa/opt/mod.rs index 38004cdf151..a9784d4c7cf 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mod.rs @@ -7,6 +7,7 @@ mod array_set; mod as_slice_length; mod assert_constant; +mod basic_conditional; mod brillig_array_gets; pub(crate) mod brillig_entry_points; mod check_u128_mul_overflow; diff --git a/compiler/noirc_evaluator/src/ssa/opt/preprocess_fns.rs b/compiler/noirc_evaluator/src/ssa/opt/preprocess_fns.rs index c4f09ac94fe..6fa1e88ee2d 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/preprocess_fns.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/preprocess_fns.rs @@ -1,8 +1,8 @@ //! Pre-process functions before inlining them into others. use crate::ssa::{ - ir::function::{Function, RuntimeType}, Ssa, + ir::function::{Function, RuntimeType}, }; use super::inlining::{self, InlineInfo}; diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs index e36be71aeea..b4427a1c91b 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, sync::Arc}; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use crate::ssa::{ ir::{ @@ -167,6 +167,7 @@ impl Context<'_> { let lhs_typ = self.function.dfg.type_of_value(lhs).unwrap_numeric(); let base = self.field_constant(FieldElement::from(2_u128)); let pow = self.pow(base, rhs); + let pow = self.pow_or_max_for_bit_size(pow, rhs, bit_size, lhs_typ); let pow = self.insert_cast(pow, lhs_typ); if lhs_typ.is_unsigned() { // unsigned right bit shift is just a normal division @@ -205,6 +206,53 @@ impl Context<'_> { } } + /// Returns `pow` or the maximum value allowed for `typ` if 2^rhs is guaranteed to exceed that maximum. + fn pow_or_max_for_bit_size( + &mut self, + pow: ValueId, + rhs: ValueId, + bit_size: u32, + typ: NumericType, + ) -> ValueId { + let max = if typ.is_unsigned() { + if bit_size == 128 { u128::MAX } else { (1_u128 << bit_size) - 1 } + } else { + 1_u128 << (bit_size - 1) + }; + let max = self.field_constant(FieldElement::from(max)); + + // Here we check whether rhs is less than the bit_size: if it's not then it will overflow. + // Then we do: + // + // rhs_is_less_than_bit_size = lt rhs, bit_size + // rhs_is_not_less_than_bit_size = not rhs_is_less_than_bit_size + // pow_when_is_less_than_bit_size = rhs_is_less_than_bit_size * pow + // pow_when_is_not_less_than_bit_size = rhs_is_not_less_than_bit_size * max + // pow = add pow_when_is_less_than_bit_size, pow_when_is_not_less_than_bit_size + // + // All operations here are unchecked because they work on field types. + let rhs_typ = self.function.dfg.type_of_value(rhs).unwrap_numeric(); + let bit_size = self.numeric_constant(bit_size as u128, rhs_typ); + let rhs_is_less_than_bit_size = self.insert_binary(rhs, BinaryOp::Lt, bit_size); + let rhs_is_not_less_than_bit_size = self.insert_not(rhs_is_less_than_bit_size); + let rhs_is_less_than_bit_size = + self.insert_cast(rhs_is_less_than_bit_size, NumericType::NativeField); + let rhs_is_not_less_than_bit_size = + self.insert_cast(rhs_is_not_less_than_bit_size, NumericType::NativeField); + let pow_when_is_less_than_bit_size = + self.insert_binary(rhs_is_less_than_bit_size, BinaryOp::Mul { unchecked: true }, pow); + let pow_when_is_not_less_than_bit_size = self.insert_binary( + rhs_is_not_less_than_bit_size, + BinaryOp::Mul { unchecked: true }, + max, + ); + self.insert_binary( + pow_when_is_less_than_bit_size, + BinaryOp::Add { unchecked: true }, + pow_when_is_not_less_than_bit_size, + ) + } + /// Computes lhs^rhs via square&multiply, using the bits decomposition of rhs /// Pseudo-code of the computation: /// let mut r = 1; diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs index a2e66ccc616..44a1a0b7acf 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs @@ -10,7 +10,7 @@ //! before the [Instruction]. Continue inserting instructions until the next [Instruction::EnableSideEffectsIf] is encountered. use std::collections::HashSet; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use crate::ssa::{ ir::{ diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs index 8dde79a3c60..94b0c1d0a85 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs @@ -1,6 +1,6 @@ use std::collections::hash_map::Entry; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use fxhash::FxHashMap as HashMap; use crate::ssa::ir::function::RuntimeType; @@ -8,6 +8,7 @@ use crate::ssa::ir::instruction::Hint; use crate::ssa::ir::types::NumericType; use crate::ssa::ir::value::ValueId; use crate::ssa::{ + Ssa, ir::{ dfg::DataFlowGraph, function::Function, @@ -16,7 +17,6 @@ use crate::ssa::{ value::Value, }, opt::flatten_cfg::value_merger::ValueMerger, - Ssa, }; impl Ssa { diff --git a/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs index e3cf3139d1c..3d812870c06 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs @@ -295,6 +295,7 @@ fn try_inline_into_predecessor( #[cfg(test)] mod test { use crate::ssa::{ + Ssa, function_builder::FunctionBuilder, ir::{ instruction::{BinaryOp, TerminatorInstruction}, @@ -302,7 +303,6 @@ mod test { types::Type, }, opt::assert_normalized_ssa_equals, - Ssa, }; use acvm::acir::AcirField; diff --git a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs index f92d7ab4b15..43afb9fa41a 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -20,7 +20,7 @@ //! only used by Brillig bytecode. use std::collections::BTreeSet; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use im::HashSet; use crate::{ @@ -1033,9 +1033,9 @@ mod tests { use test_case::test_case; use crate::errors::RuntimeError; - use crate::ssa::{ir::value::ValueId, opt::assert_normalized_ssa_equals, Ssa}; + use crate::ssa::{Ssa, ir::value::ValueId, opt::assert_normalized_ssa_equals}; - use super::{is_new_size_ok, BoilerplateStats, Loops}; + use super::{BoilerplateStats, Loops, is_new_size_ok}; /// Tries to unroll all loops in each SSA function once, calling the `Function` directly, /// bypassing the iterative loop done by the SSA which does further optimisations. diff --git a/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs b/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs index fc9b1ae98bc..d7ca5832f06 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs @@ -15,8 +15,8 @@ use crate::ssa::{ }; use super::{ - ast::AssertMessage, Identifier, ParsedBlock, ParsedFunction, ParsedGlobal, ParsedGlobalValue, - ParsedInstruction, ParsedSsa, ParsedTerminator, ParsedValue, RuntimeType, Ssa, SsaError, Type, + Identifier, ParsedBlock, ParsedFunction, ParsedGlobal, ParsedGlobalValue, ParsedInstruction, + ParsedSsa, ParsedTerminator, ParsedValue, RuntimeType, Ssa, SsaError, Type, ast::AssertMessage, }; impl ParsedSsa { diff --git a/compiler/noirc_evaluator/src/ssa/parser/mod.rs b/compiler/noirc_evaluator/src/ssa/parser/mod.rs index ebbe6fb0095..9f4d38648e2 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/mod.rs @@ -5,11 +5,11 @@ use std::{ }; use super::{ + Ssa, ir::{ instruction::BinaryOp, types::{NumericType, Type}, }, - Ssa, }; use acvm::{AcirField, FieldElement}; @@ -675,11 +675,7 @@ impl<'a> Parser<'a> { } fn parse_value_or_error(&mut self) -> ParseResult { - if let Some(value) = self.parse_value()? { - Ok(value) - } else { - self.expected_value() - } + if let Some(value) = self.parse_value()? { Ok(value) } else { self.expected_value() } } fn parse_value(&mut self) -> ParseResult> { @@ -852,11 +848,7 @@ impl<'a> Parser<'a> { } fn eat_ident_or_error(&mut self) -> ParseResult { - if let Some(ident) = self.eat_ident()? { - Ok(ident) - } else { - self.expected_identifier() - } + if let Some(ident) = self.eat_ident()? { Ok(ident) } else { self.expected_identifier() } } fn eat_int(&mut self) -> ParseResult> { @@ -879,11 +871,7 @@ impl<'a> Parser<'a> { } fn eat_int_or_error(&mut self) -> ParseResult { - if let Some(int) = self.eat_int()? { - Ok(int) - } else { - self.expected_int() - } + if let Some(int) = self.eat_int()? { Ok(int) } else { self.expected_int() } } fn eat_int_type(&mut self) -> ParseResult> { @@ -933,11 +921,7 @@ impl<'a> Parser<'a> { } fn eat_or_error(&mut self, token: Token) -> ParseResult<()> { - if self.eat(token.clone())? { - Ok(()) - } else { - self.expected_token(token) - } + if self.eat(token.clone())? { Ok(()) } else { self.expected_token(token) } } fn at(&self, token: Token) -> bool { diff --git a/compiler/noirc_evaluator/src/ssa/parser/tests.rs b/compiler/noirc_evaluator/src/ssa/parser/tests.rs index 358c2e89a41..a865a31a060 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/tests.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/tests.rs @@ -1,7 +1,7 @@ #![cfg(test)] use crate::{ - ssa::{opt::assert_normalized_ssa_equals, Ssa}, + ssa::{Ssa, opt::assert_normalized_ssa_equals}, trim_leading_whitespace_from_lines, }; diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index 7e8bc8765b7..5db3ecb91b7 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::sync::{Arc, Mutex, RwLock}; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use iter_extended::vecmap; use noirc_errors::Location; use noirc_frontend::ast::{BinaryOpKind, Signedness}; @@ -20,8 +20,8 @@ use crate::ssa::ir::map::AtomicCounter; use crate::ssa::ir::types::{NumericType, Type}; use crate::ssa::ir::value::ValueId; -use super::value::{Tree, Value, Values}; use super::GlobalsGraph; +use super::value::{Tree, Value, Values}; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; /// The FunctionContext is the main context object for translating a @@ -755,11 +755,7 @@ impl<'a> FunctionContext<'a> { Ok(match lvalue { ast::LValue::Ident(ident) => { let (reference, should_auto_deref) = self.ident_lvalue(ident); - if should_auto_deref { - LValue::Dereference { reference } - } else { - LValue::Ident - } + if should_auto_deref { LValue::Dereference { reference } } else { LValue::Ident } } ast::LValue::Index { array, index, location, .. } => { self.index_lvalue(array, index, location)?.2 diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index 096e5cbad86..398e5267695 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -930,6 +930,13 @@ impl FunctionReturnType { FunctionReturnType::Ty(typ) => Cow::Borrowed(typ), } } + + pub fn location(&self) -> Location { + match self { + FunctionReturnType::Default(location) => *location, + FunctionReturnType::Ty(typ) => typ.location, + } + } } impl Display for FunctionReturnType { diff --git a/compiler/noirc_frontend/src/ast/mod.rs b/compiler/noirc_frontend/src/ast/mod.rs index 20f92ffb38a..8e74ce8877e 100644 --- a/compiler/noirc_frontend/src/ast/mod.rs +++ b/compiler/noirc_frontend/src/ast/mod.rs @@ -35,10 +35,10 @@ pub use traits::*; pub use type_alias::*; use crate::{ + BinaryTypeOperator, node_interner::{InternedUnresolvedTypeData, QuotedTypeId}, parser::{ParserError, ParserErrorReason}, token::IntType, - BinaryTypeOperator, }; use acvm::acir::AcirField; use iter_extended::vecmap; diff --git a/compiler/noirc_frontend/src/ast/statement.rs b/compiler/noirc_frontend/src/ast/statement.rs index c44bfa6389c..78b29b8c1fd 100644 --- a/compiler/noirc_frontend/src/ast/statement.rs +++ b/compiler/noirc_frontend/src/ast/statement.rs @@ -1,7 +1,7 @@ use std::fmt::Display; -use acvm::acir::AcirField; use acvm::FieldElement; +use acvm::acir::AcirField; use iter_extended::vecmap; use noirc_errors::{Located, Location, Span}; @@ -11,8 +11,8 @@ use super::{ MethodCallExpression, UnresolvedType, }; use crate::ast::UnresolvedTypeData; -use crate::elaborator::types::SELF_TYPE_NAME; use crate::elaborator::Turbofish; +use crate::elaborator::types::SELF_TYPE_NAME; use crate::node_interner::{ InternedExpressionKind, InternedPattern, InternedStatementKind, NodeInterner, }; diff --git a/compiler/noirc_frontend/src/ast/traits.rs b/compiler/noirc_frontend/src/ast/traits.rs index d2ad40e597d..d7cc48ec742 100644 --- a/compiler/noirc_frontend/src/ast/traits.rs +++ b/compiler/noirc_frontend/src/ast/traits.rs @@ -197,11 +197,7 @@ impl Display for TraitItem { "{unconstrained}{visibility}{is_comptime}fn {name}<{generics}>({parameters}) -> {return_type} where {where_clause}" )?; - if let Some(body) = body { - write!(f, "{body}") - } else { - write!(f, ";") - } + if let Some(body) = body { write!(f, "{body}") } else { write!(f, ";") } } TraitItem::Constant { name, typ, default_value } => { write!(f, "let {name}: {typ}")?; diff --git a/compiler/noirc_frontend/src/ast/visitor.rs b/compiler/noirc_frontend/src/ast/visitor.rs index b91d5c5049e..b2142f26655 100644 --- a/compiler/noirc_frontend/src/ast/visitor.rs +++ b/compiler/noirc_frontend/src/ast/visitor.rs @@ -1,6 +1,7 @@ use noirc_errors::Span; use crate::{ + ParsedModule, QuotedType, ast::{ ArrayLiteral, AsTraitPath, AssignStatement, BlockExpression, CallExpression, CastExpression, ConstrainExpression, ConstructorExpression, Expression, ExpressionKind, @@ -17,7 +18,6 @@ use crate::{ parser::{Item, ItemKind, ParsedSubModule}, signed_field::SignedField, token::{FmtStrFragment, MetaAttribute, SecondaryAttribute, Tokens}, - ParsedModule, QuotedType, }; use super::{ diff --git a/compiler/noirc_frontend/src/debug/mod.rs b/compiler/noirc_frontend/src/debug/mod.rs index a8bcb6ca9cb..48bed1c4199 100644 --- a/compiler/noirc_frontend/src/debug/mod.rs +++ b/compiler/noirc_frontend/src/debug/mod.rs @@ -382,7 +382,7 @@ impl DebugInstrumenter { fn walk_expr(&mut self, expr: &mut ast::Expression) { match &mut expr.kind { - ast::ExpressionKind::Block(ast::BlockExpression { ref mut statements, .. }) => { + ast::ExpressionKind::Block(ast::BlockExpression { statements, .. }) => { self.scope.push(HashMap::default()); self.walk_scope(statements, expr.location); } @@ -396,19 +396,19 @@ impl DebugInstrumenter { ast::ExpressionKind::Call(call_expr) => { // TODO: push a stack frame or something here? self.walk_expr(&mut call_expr.func); - call_expr.arguments.iter_mut().for_each(|ref mut expr| { + call_expr.arguments.iter_mut().for_each(|expr| { self.walk_expr(expr); }); } ast::ExpressionKind::MethodCall(mc_expr) => { // TODO: also push a stack frame here self.walk_expr(&mut mc_expr.object); - mc_expr.arguments.iter_mut().for_each(|ref mut expr| { + mc_expr.arguments.iter_mut().for_each(|expr| { self.walk_expr(expr); }); } ast::ExpressionKind::Constructor(c_expr) => { - c_expr.fields.iter_mut().for_each(|(_id, ref mut expr)| { + c_expr.fields.iter_mut().for_each(|(_id, expr)| { self.walk_expr(expr); }); } @@ -492,7 +492,7 @@ impl DebugInstrumenter { ast::StatementKind::Semi(expr) => { self.walk_expr(expr); } - ast::StatementKind::For(ref mut for_stmt) => { + ast::StatementKind::For(for_stmt) => { self.walk_for(for_stmt); } _ => {} // Constrain, Error diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index 6c9937dedc3..7091f7b261c 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -4,6 +4,7 @@ use iter_extended::vecmap; use noirc_errors::Location; use crate::{ + Type, TypeBindings, UnificationError, ast::{Documented, Expression, ExpressionKind}, hir::{ comptime::{Interpreter, InterpreterError, Value}, @@ -21,7 +22,6 @@ use crate::{ node_interner::{DefinitionKind, DependencyId, FuncId, NodeInterner, TraitId, TypeId}, parser::{Item, ItemKind}, token::{MetaAttribute, SecondaryAttribute}, - Type, TypeBindings, UnificationError, }; use super::{ElaborateReason, Elaborator, FunctionContext, ResolverMeta}; diff --git a/compiler/noirc_frontend/src/elaborator/enums.rs b/compiler/noirc_frontend/src/elaborator/enums.rs index 80a58fcf2c3..90849a750d5 100644 --- a/compiler/noirc_frontend/src/elaborator/enums.rs +++ b/compiler/noirc_frontend/src/elaborator/enums.rs @@ -5,6 +5,7 @@ use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; use crate::{ + DataType, Kind, Shared, Type, ast::{ ConstructorExpression, EnumVariant, Expression, ExpressionKind, FunctionKind, Ident, Literal, NoirEnumeration, StatementKind, UnresolvedType, Visibility, @@ -22,7 +23,6 @@ use crate::{ node_interner::{DefinitionId, DefinitionKind, ExprId, FunctionModifiers, GlobalValue, TypeId}, signed_field::SignedField, token::Attributes, - DataType, Kind, Shared, Type, }; use super::Elaborator; diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 9624735f6fa..a4cb7291455 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -4,13 +4,14 @@ use noirc_errors::{Located, Location}; use rustc_hash::FxHashSet as HashSet; use crate::{ + DataType, Kind, QuotedType, Shared, Type, ast::{ - ArrayLiteral, BinaryOpKind, BlockExpression, CallExpression, CastExpression, + ArrayLiteral, AsTraitPath, BinaryOpKind, BlockExpression, CallExpression, CastExpression, ConstrainExpression, ConstrainKind, ConstructorExpression, Expression, ExpressionKind, Ident, IfExpression, IndexExpression, InfixExpression, ItemVisibility, Lambda, Literal, MatchExpression, MemberAccessExpression, MethodCallExpression, Path, PathSegment, - PrefixExpression, StatementKind, UnaryOp, UnresolvedTypeData, UnresolvedTypeExpression, - UnsafeExpression, + PrefixExpression, StatementKind, TraitBound, UnaryOp, UnresolvedTraitConstraint, + UnresolvedTypeData, UnresolvedTypeExpression, UnsafeExpression, }, hir::{ comptime::{self, InterpreterError}, @@ -18,14 +19,14 @@ use crate::{ resolution::{ errors::ResolverError, import::PathResolutionError, visibility::method_call_is_visible, }, - type_check::{generics::TraitGenerics, TypeCheckError}, + type_check::{TypeCheckError, generics::TraitGenerics}, }, hir_def::{ expr::{ HirArrayLiteral, HirBinaryOp, HirBlockExpression, HirCallExpression, HirCastExpression, HirConstrainExpression, HirConstructorExpression, HirExpression, HirIdent, HirIfExpression, HirIndexExpression, HirInfixExpression, HirLambda, HirLiteral, - HirMemberAccess, HirMethodCallExpression, HirPrefixExpression, + HirMemberAccess, HirMethodCallExpression, HirPrefixExpression, ImplKind, TraitMethod, }, stmt::{HirLetStatement, HirPattern, HirStatement}, traits::{ResolvedTraitBound, TraitConstraint}, @@ -34,7 +35,6 @@ use crate::{ DefinitionId, DefinitionKind, ExprId, FuncId, InternedStatementKind, StmtId, TraitMethodId, }, token::{FmtStrFragment, Tokens}, - DataType, Kind, QuotedType, Shared, Type, }; use super::{Elaborator, LambdaContext, UnsafeBlockStatus}; @@ -94,11 +94,8 @@ impl Elaborator<'_> { self.push_err(ResolverError::UnquoteUsedOutsideQuote { location: expr.location }); (HirExpression::Error, Type::Error) } - ExpressionKind::AsTraitPath(_) => { - self.push_err(ResolverError::AsTraitPathNotYetImplemented { - location: expr.location, - }); - (HirExpression::Error, Type::Error) + ExpressionKind::AsTraitPath(path) => { + return self.elaborate_as_trait_path(path); } ExpressionKind::TypePath(path) => return self.elaborate_type_path(path), }; @@ -1344,4 +1341,55 @@ impl Elaborator<'_> { let (expr_id, typ) = self.inline_comptime_value(result, location); Some((self.interner.expression(&expr_id), typ)) } + + fn elaborate_as_trait_path(&mut self, path: AsTraitPath) -> (ExprId, Type) { + let location = path.typ.location.merge(path.trait_path.location); + + let constraint = UnresolvedTraitConstraint { + typ: path.typ, + trait_bound: TraitBound { + trait_path: path.trait_path, + trait_id: None, + trait_generics: path.trait_generics, + }, + }; + + let typ = self.resolve_type(constraint.typ.clone()); + let Some(trait_bound) = self.resolve_trait_bound(&constraint.trait_bound) else { + // resolve_trait_bound only returns None if it has already issued an error, so don't + // issue another here. + let error = self.interner.push_expr_full(HirExpression::Error, location, Type::Error); + return (error, Type::Error); + }; + + let constraint = TraitConstraint { typ, trait_bound }; + + let the_trait = self.interner.get_trait(constraint.trait_bound.trait_id); + let Some(method) = the_trait.find_method(&path.impl_item.0.contents) else { + let trait_name = the_trait.name.to_string(); + let method_name = path.impl_item.to_string(); + let location = path.impl_item.location(); + self.push_err(ResolverError::NoSuchMethodInTrait { trait_name, method_name, location }); + let error = self.interner.push_expr_full(HirExpression::Error, location, Type::Error); + return (error, Type::Error); + }; + + let trait_method = + TraitMethod { method_id: method, constraint: constraint.clone(), assumed: true }; + + let definition_id = self.interner.trait_method_id(trait_method.method_id); + + let ident = HirIdent { + location: path.impl_item.location(), + id: definition_id, + impl_kind: ImplKind::TraitMethod(trait_method), + }; + + let id = self.interner.push_expr(HirExpression::Ident(ident.clone(), None)); + self.interner.push_expr_location(id, location); + + let typ = self.type_check_variable(ident, id, None); + self.interner.push_expr_type(id, typ.clone()); + (id, typ) + } } diff --git a/compiler/noirc_frontend/src/elaborator/lints.rs b/compiler/noirc_frontend/src/elaborator/lints.rs index c60d41b85e2..4ce797c6e07 100644 --- a/compiler/noirc_frontend/src/elaborator/lints.rs +++ b/compiler/noirc_frontend/src/elaborator/lints.rs @@ -1,4 +1,5 @@ use crate::{ + Type, ast::{Ident, NoirFunction, Signedness, UnaryOp, Visibility}, graph::CrateId, hir::{ @@ -13,7 +14,6 @@ use crate::{ node_interner::{ DefinitionId, DefinitionKind, ExprId, FuncId, FunctionModifiers, NodeInterner, }, - Type, }; use noirc_errors::{Located, Location}; @@ -299,11 +299,7 @@ fn can_return_without_recursing(interner: &NodeInterner, func_id: FuncId, expr_i return true; } let definition = interner.definition(ident.id); - if let DefinitionKind::Function(id) = definition.kind { - func_id != id - } else { - true - } + if let DefinitionKind::Function(id) = definition.kind { func_id != id } else { true } } HirExpression::Block(b) => check_block(b), HirExpression::Prefix(e) => check(e.rhs), diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 3a6a2c8eaea..27726744fd2 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -4,6 +4,15 @@ use std::{ }; use crate::{ + DataType, StructField, TypeBindings, + ast::{ItemVisibility, UnresolvedType}, + graph::CrateGraph, + hir_def::traits::ResolvedTraitBound, + node_interner::GlobalValue, + usage_tracker::UsageTracker, +}; +use crate::{ + EnumVariant, Shared, Type, TypeVariable, ast::{ BlockExpression, FunctionKind, GenericTypeArgs, Ident, NoirFunction, NoirStruct, Param, Path, Pattern, TraitBound, UnresolvedGeneric, UnresolvedGenerics, @@ -11,20 +20,20 @@ use crate::{ }, graph::CrateId, hir::{ + Context, comptime::ComptimeError, def_collector::{ dc_crate::{ - filter_literal_globals, CollectedItems, CompilationError, ImplMap, UnresolvedEnum, - UnresolvedFunctions, UnresolvedGlobal, UnresolvedStruct, UnresolvedTraitImpl, - UnresolvedTypeAlias, + CollectedItems, CompilationError, ImplMap, UnresolvedEnum, UnresolvedFunctions, + UnresolvedGlobal, UnresolvedStruct, UnresolvedTraitImpl, UnresolvedTypeAlias, + filter_literal_globals, }, errors::DefCollectorErrorKind, }, - def_map::{DefMaps, LocalModuleId, ModuleData, ModuleId, MAIN_FUNCTION}, + def_map::{DefMaps, LocalModuleId, MAIN_FUNCTION, ModuleData, ModuleId}, resolution::errors::ResolverError, scope::ScopeForest as GenericScopeForest, - type_check::{generics::TraitGenerics, TypeCheckError}, - Context, + type_check::{TypeCheckError, generics::TraitGenerics}, }, hir_def::{ expr::{HirCapturedVar, HirIdent}, @@ -38,15 +47,6 @@ use crate::{ }, parser::{ParserError, ParserErrorReason}, token::SecondaryAttribute, - EnumVariant, Shared, Type, TypeVariable, -}; -use crate::{ - ast::{ItemVisibility, UnresolvedType}, - graph::CrateGraph, - hir_def::traits::ResolvedTraitBound, - node_interner::GlobalValue, - usage_tracker::UsageTracker, - DataType, StructField, TypeBindings, }; mod comptime; @@ -750,11 +750,7 @@ impl<'context> Elaborator<'context> { pub fn resolve_module_by_path(&mut self, path: Path) -> Option { match self.resolve_path(path.clone()) { Ok(PathResolution { item: PathResolutionItem::Module(module_id), errors }) => { - if errors.is_empty() { - Some(module_id) - } else { - None - } + if errors.is_empty() { Some(module_id) } else { None } } _ => None, } @@ -1268,9 +1264,13 @@ impl<'context> Elaborator<'context> { self.check_parent_traits_are_implemented(&trait_impl); self.remove_trait_impl_assumed_trait_implementations(trait_impl.impl_id); - for (module, function, _) in &trait_impl.methods.functions { + for (module, function, noir_function) in &trait_impl.methods.functions { self.local_module = *module; - let errors = check_trait_impl_method_matches_declaration(self.interner, *function); + let errors = check_trait_impl_method_matches_declaration( + self.interner, + *function, + noir_function, + ); self.push_errors(errors.into_iter().map(|error| error.into())); } diff --git a/compiler/noirc_frontend/src/elaborator/path_resolution.rs b/compiler/noirc_frontend/src/elaborator/path_resolution.rs index a1d3eb8caca..c0dfa90d36c 100644 --- a/compiler/noirc_frontend/src/elaborator/path_resolution.rs +++ b/compiler/noirc_frontend/src/elaborator/path_resolution.rs @@ -3,7 +3,7 @@ use noirc_errors::Location; use crate::ast::{Ident, Path, PathKind, UnresolvedType}; use crate::hir::def_map::{ModuleData, ModuleDefId, ModuleId, PerNs}; -use crate::hir::resolution::import::{resolve_path_kind, PathResolutionError}; +use crate::hir::resolution::import::{PathResolutionError, resolve_path_kind}; use crate::hir::resolution::errors::ResolverError; use crate::hir::resolution::visibility::item_in_module_is_visible; @@ -12,8 +12,8 @@ use crate::locations::ReferencesTracker; use crate::node_interner::{FuncId, GlobalId, TraitId, TypeAliasId, TypeId}; use crate::{Shared, Type, TypeAlias}; -use super::types::SELF_TYPE_NAME; use super::Elaborator; +use super::types::SELF_TYPE_NAME; #[derive(Debug)] pub(crate) struct PathResolution { diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index f480f339a5d..6ad8e1ec04c 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -3,9 +3,10 @@ use noirc_errors::Location; use rustc_hash::FxHashSet as HashSet; use crate::{ + DataType, Kind, Shared, Type, TypeAlias, TypeBindings, ast::{ - Expression, ExpressionKind, Ident, ItemVisibility, Path, Pattern, TypePath, UnresolvedType, - ERROR_IDENT, + ERROR_IDENT, Expression, ExpressionKind, Ident, ItemVisibility, Path, Pattern, TypePath, + UnresolvedType, }, hir::{ def_collector::dc_crate::CompilationError, @@ -17,10 +18,9 @@ use crate::{ stmt::HirPattern, }, node_interner::{DefinitionId, DefinitionKind, ExprId, FuncId, GlobalId, TraitImplKind}, - DataType, Kind, Shared, Type, TypeAlias, TypeBindings, }; -use super::{path_resolution::PathResolutionItem, Elaborator, ResolverMeta}; +use super::{Elaborator, ResolverMeta, path_resolution::PathResolutionItem}; impl Elaborator<'_> { pub(super) fn elaborate_pattern( diff --git a/compiler/noirc_frontend/src/elaborator/scope.rs b/compiler/noirc_frontend/src/elaborator/scope.rs index 6e2649d6441..9955d874927 100644 --- a/compiler/noirc_frontend/src/elaborator/scope.rs +++ b/compiler/noirc_frontend/src/elaborator/scope.rs @@ -1,17 +1,17 @@ use noirc_errors::Located; -use crate::ast::{Ident, Path, ERROR_IDENT}; +use crate::ast::{ERROR_IDENT, Ident, Path}; use crate::hir::def_map::{LocalModuleId, ModuleId}; use crate::hir::scope::{Scope as GenericScope, ScopeTree as GenericScopeTree}; use crate::{ + DataType, Shared, hir::resolution::errors::ResolverError, hir_def::{ expr::{HirCapturedVar, HirIdent}, traits::Trait, }, node_interner::{DefinitionId, TraitId, TypeId}, - DataType, Shared, }; use crate::{Type, TypeAlias}; diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index 52afa5aaa08..f00b2a87b1e 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -1,6 +1,7 @@ use noirc_errors::Location; use crate::{ + DataType, Type, ast::{ AssignStatement, Expression, ForLoopStatement, ForRange, Ident, ItemVisibility, LValue, LetStatement, Path, Statement, StatementKind, WhileStatement, @@ -17,10 +18,9 @@ use crate::{ stmt::{HirAssignStatement, HirForStatement, HirLValue, HirLetStatement, HirStatement}, }, node_interner::{DefinitionId, DefinitionKind, GlobalId, StmtId}, - DataType, Type, }; -use super::{lints, Elaborator, Loop}; +use super::{Elaborator, Loop, lints}; impl Elaborator<'_> { fn elaborate_statement_value(&mut self, statement: Statement) -> (HirStatement, Type) { @@ -91,6 +91,7 @@ impl Elaborator<'_> { let type_contains_unspecified = let_stmt.r#type.contains_unspecified(); let annotated_type = self.resolve_inferred_type(let_stmt.r#type); + let pattern_location = let_stmt.pattern.location(); let expr_location = let_stmt.expression.location; let (expression, expr_type) = self.elaborate_expression_with_target_type(let_stmt.expression, Some(&annotated_type)); @@ -98,8 +99,11 @@ impl Elaborator<'_> { // Require the top-level of a global's type to be fully-specified if type_contains_unspecified && global_id.is_some() { let expected_type = annotated_type.clone(); - let error = - ResolverError::UnspecifiedGlobalType { location: expr_location, expected_type }; + let error = ResolverError::UnspecifiedGlobalType { + pattern_location, + expr_location, + expected_type, + }; self.push_err(error); } @@ -205,11 +209,10 @@ impl Elaborator<'_> { ); // Check that start range and end range have the same types - let range_location = start_location.merge(end_location); self.unify(&start_range_type, &end_range_type, || TypeCheckError::TypeMismatch { expected_typ: start_range_type.to_string(), expr_typ: end_range_type.to_string(), - expr_location: range_location, + expr_location: end_location, }); let expected_type = self.polymorphic_integer(); @@ -217,7 +220,7 @@ impl Elaborator<'_> { self.unify(&start_range_type, &expected_type, || TypeCheckError::TypeCannotBeUsed { typ: start_range_type.clone(), place: "for loop", - location: range_location, + location: start_location, }); self.interner.push_definition_type(identifier.id, start_range_type); diff --git a/compiler/noirc_frontend/src/elaborator/trait_impls.rs b/compiler/noirc_frontend/src/elaborator/trait_impls.rs index 392b5e0ec46..63befb67b09 100644 --- a/compiler/noirc_frontend/src/elaborator/trait_impls.rs +++ b/compiler/noirc_frontend/src/elaborator/trait_impls.rs @@ -1,4 +1,5 @@ use crate::{ + ResolvedGeneric, ast::{Ident, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression}, graph::CrateId, hir::def_collector::{ @@ -6,13 +7,12 @@ use crate::{ errors::DefCollectorErrorKind, }, node_interner::TraitImplId, - ResolvedGeneric, }; use crate::{ + Type, hir::def_collector::errors::DuplicateType, hir_def::traits::{TraitConstraint, TraitFunction}, node_interner::{FuncId, TraitId}, - Type, }; use rustc_hash::FxHashSet as HashSet; diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index 3b0666409da..a931dde93de 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -4,6 +4,7 @@ use iter_extended::vecmap; use noirc_errors::Location; use crate::{ + ResolvedGeneric, Type, TypeBindings, ast::{ BlockExpression, FunctionDefinition, FunctionKind, FunctionReturnType, Ident, ItemVisibility, NoirFunction, TraitItem, UnresolvedGeneric, UnresolvedGenerics, @@ -15,7 +16,6 @@ use crate::{ traits::{ResolvedTraitBound, TraitFunction}, }, node_interner::{DependencyId, FuncId, NodeInterner, ReferenceId, TraitId}, - ResolvedGeneric, Type, TypeBindings, }; use super::Elaborator; @@ -273,6 +273,7 @@ impl Elaborator<'_> { pub(crate) fn check_trait_impl_method_matches_declaration( interner: &mut NodeInterner, function: FuncId, + noir_function: &NoirFunction, ) -> Vec { let meta = interner.function_meta(&function); let modifiers = interner.function_modifiers(&function); @@ -349,6 +350,8 @@ pub(crate) fn check_trait_impl_method_matches_declaration( definition_type, method_name, &meta.parameters, + &meta.return_type, + noir_function, meta.name.location, &trait_info.name.0.contents, &mut errors, @@ -358,11 +361,14 @@ pub(crate) fn check_trait_impl_method_matches_declaration( errors } +#[allow(clippy::too_many_arguments)] fn check_function_type_matches_expected_type( expected: &Type, actual: &Type, method_name: &str, actual_parameters: &Parameters, + actual_return_type: &FunctionReturnType, + noir_function: &NoirFunction, location: Location, trait_name: &str, errors: &mut Vec, @@ -381,11 +387,16 @@ fn check_function_type_matches_expected_type( if params_a.len() == params_b.len() { for (i, (a, b)) in params_a.iter().zip(params_b.iter()).enumerate() { if a.try_unify(b, &mut bindings).is_err() { + let parameter_location = noir_function.def.parameters.get(i); + let parameter_location = parameter_location.map(|param| param.typ.location); + let parameter_location = + parameter_location.unwrap_or_else(|| actual_parameters.0[i].0.location()); + errors.push(TypeCheckError::TraitMethodParameterTypeMismatch { method_name: method_name.to_string(), expected_typ: a.to_string(), actual_typ: b.to_string(), - parameter_location: actual_parameters.0[i].0.location(), + parameter_location, parameter_index: i + 1, }); } @@ -395,7 +406,7 @@ fn check_function_type_matches_expected_type( errors.push(TypeCheckError::TypeMismatch { expected_typ: ret_a.to_string(), expr_typ: ret_b.to_string(), - expr_location: location, + expr_location: actual_return_type.location(), }); } } else { diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 9ceb176b010..fb643161026 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -6,6 +6,7 @@ use noirc_errors::Location; use rustc_hash::FxHashMap as HashMap; use crate::{ + Generics, Kind, ResolvedGeneric, Type, TypeBinding, TypeBindings, UnificationError, ast::{ AsTraitPath, BinaryOpKind, GenericTypeArgs, Ident, IntegerBitSize, Path, PathKind, Signedness, UnaryOp, UnresolvedGeneric, UnresolvedGenerics, UnresolvedType, @@ -13,11 +14,11 @@ use crate::{ }, hir::{ def_collector::dc_crate::CompilationError, - def_map::{fully_qualified_module_path, ModuleDefId}, + def_map::{ModuleDefId, fully_qualified_module_path}, resolution::{errors::ResolverError, import::PathResolutionError}, type_check::{ - generics::{Generic, TraitGenerics}, NoMatchingImplFoundError, Source, TypeCheckError, + generics::{Generic, TraitGenerics}, }, }, hir_def::{ @@ -35,10 +36,9 @@ use crate::{ }, signed_field::SignedField, token::SecondaryAttribute, - Generics, Kind, ResolvedGeneric, Type, TypeBinding, TypeBindings, UnificationError, }; -use super::{lints, path_resolution::PathResolutionItem, Elaborator, UnsafeBlockStatus}; +use super::{Elaborator, UnsafeBlockStatus, lints, path_resolution::PathResolutionItem}; pub const SELF_TYPE_NAME: &str = "Self"; @@ -174,8 +174,8 @@ impl Elaborator<'_> { if !kind.unifies(&resolved_type.kind()) { let expected_typ_err = CompilationError::TypeError(TypeCheckError::TypeKindMismatch { - expected_kind: kind.to_string(), - expr_kind: resolved_type.kind().to_string(), + expected_kind: kind.clone(), + expr_kind: resolved_type.kind(), expr_location: location, }); self.push_err(expected_typ_err); @@ -523,8 +523,8 @@ impl Elaborator<'_> { (Type::Constant(lhs, lhs_kind), Type::Constant(rhs, rhs_kind)) => { if !lhs_kind.unifies(&rhs_kind) { self.push_err(TypeCheckError::TypeKindMismatch { - expected_kind: lhs_kind.to_string(), - expr_kind: rhs_kind.to_string(), + expected_kind: lhs_kind, + expr_kind: rhs_kind, expr_location: location, }); return Type::Error; @@ -557,8 +557,8 @@ impl Elaborator<'_> { fn check_kind(&mut self, typ: Type, expected_kind: &Kind, location: Location) -> Type { if !typ.kind().unifies(expected_kind) { self.push_err(TypeCheckError::TypeKindMismatch { - expected_kind: expected_kind.to_string(), - expr_kind: typ.kind().to_string(), + expected_kind: expected_kind.clone(), + expr_kind: typ.kind(), expr_location: location, }); return Type::Error; @@ -1052,7 +1052,7 @@ impl Elaborator<'_> { // Matches on TypeVariable must be first to follow any type // bindings. (TypeVariable(var), other) | (other, TypeVariable(var)) => { - if let TypeBinding::Bound(ref binding) = &*var.borrow() { + if let TypeBinding::Bound(binding) = &*var.borrow() { return self.comparator_operand_type_rules(other, binding, op, location); } @@ -1179,7 +1179,7 @@ impl Elaborator<'_> { }; return Ok((lhs_type.clone(), use_impl)); } - if let TypeBinding::Bound(ref binding) = &*int.borrow() { + if let TypeBinding::Bound(binding) = &*int.borrow() { return self.infix_operand_type_rules(binding, op, other, location); } let use_impl = self.bind_type_variables_for_infix(lhs_type, op, rhs_type, location); @@ -1265,7 +1265,7 @@ impl Elaborator<'_> { // Matches on TypeVariable must be first so that we follow any type // bindings. TypeVariable(int) => { - if let TypeBinding::Bound(ref binding) = &*int.borrow() { + if let TypeBinding::Bound(binding) = &*int.borrow() { return self.prefix_operand_type_rules(op, binding, location); } diff --git a/compiler/noirc_frontend/src/graph/mod.rs b/compiler/noirc_frontend/src/graph/mod.rs index c007d6792bd..0ce744aded5 100644 --- a/compiler/noirc_frontend/src/graph/mod.rs +++ b/compiler/noirc_frontend/src/graph/mod.rs @@ -87,7 +87,7 @@ impl FromStr for CrateName { #[cfg(test)] mod crate_name { - use super::{CrateName, CHARACTER_BLACK_LIST}; + use super::{CHARACTER_BLACK_LIST, CrateName}; #[test] fn it_rejects_empty_string() { @@ -379,7 +379,7 @@ mod tests { use super::{CrateGraph, FileId}; fn dummy_file_ids(n: usize) -> Vec { - use fm::{FileMap, FILE_EXTENSION}; + use fm::{FILE_EXTENSION, FileMap}; let mut fm = FileMap::default(); let mut vec_ids = Vec::with_capacity(n); diff --git a/compiler/noirc_frontend/src/hir/comptime/display.rs b/compiler/noirc_frontend/src/hir/comptime/display.rs index de16415520b..c0283d9701b 100644 --- a/compiler/noirc_frontend/src/hir/comptime/display.rs +++ b/compiler/noirc_frontend/src/hir/comptime/display.rs @@ -4,6 +4,7 @@ use iter_extended::vecmap; use noirc_errors::Location; use crate::{ + Type, ast::{ ArrayLiteral, AsTraitPath, AssignStatement, BlockExpression, CallExpression, CastExpression, ConstrainExpression, ConstructorExpression, Expression, ExpressionKind, @@ -15,12 +16,11 @@ use crate::{ hir_def::traits::TraitConstraint, node_interner::{InternedStatementKind, NodeInterner}, token::{Keyword, LocatedToken, Token}, - Type, }; use super::{ - value::{ExprValue, TypedExpr}, Value, + value::{ExprValue, TypedExpr}, }; pub(super) fn display_quoted( diff --git a/compiler/noirc_frontend/src/hir/comptime/errors.rs b/compiler/noirc_frontend/src/hir/comptime/errors.rs index 8fff67ad835..27440069c02 100644 --- a/compiler/noirc_frontend/src/hir/comptime/errors.rs +++ b/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -2,6 +2,7 @@ use std::fmt::Display; use std::rc::Rc; use crate::{ + Type, ast::TraitBound, hir::{ def_collector::dc_crate::CompilationError, @@ -9,7 +10,6 @@ use crate::{ }, parser::ParserError, signed_field::SignedField, - Type, }; use acvm::BlackBoxResolutionError; use noirc_errors::{CustomDiagnostic, Location}; diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 1e757c6d94b..5c87e70949a 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -2,12 +2,13 @@ use std::collections::VecDeque; use std::{collections::hash_map::Entry, rc::Rc}; use acvm::blackbox_solver::BigIntSolverWithId; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use im::Vector; use iter_extended::try_vecmap; use noirc_errors::Location; use rustc_hash::FxHashMap as HashMap; +use crate::TypeVariable; use crate::ast::{BinaryOpKind, FunctionKind, IntegerBitSize, Signedness, UnaryOp}; use crate::elaborator::Elaborator; use crate::graph::CrateId; @@ -22,8 +23,8 @@ use crate::monomorphization::{ use crate::node_interner::GlobalValue; use crate::signed_field::SignedField; use crate::token::{FmtStrFragment, Tokens}; -use crate::TypeVariable; use crate::{ + Shared, Type, TypeBinding, TypeBindings, hir_def::{ expr::{ HirArrayLiteral, HirBlockExpression, HirCallExpression, HirCastExpression, @@ -38,11 +39,10 @@ use crate::{ types::Kind, }, node_interner::{DefinitionId, DefinitionKind, ExprId, FuncId, NodeInterner, StmtId}, - Shared, Type, TypeBinding, TypeBindings, }; use super::errors::{IResult, InterpreterError}; -use super::value::{unwrap_rc, Closure, Value}; +use super::value::{Closure, Value, unwrap_rc}; mod builtin; mod foreign; diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 9a5f31a90fe..34a5535f63c 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -17,6 +17,7 @@ use num_bigint::BigUint; use rustc_hash::FxHashMap as HashMap; use crate::{ + Kind, QuotedType, ResolvedGeneric, Shared, Type, TypeVariable, ast::{ ArrayLiteral, BlockExpression, ConstrainKind, Expression, ExpressionKind, ForRange, FunctionKind, FunctionReturnType, Ident, IntegerBitSize, ItemVisibility, LValue, Literal, @@ -26,9 +27,9 @@ use crate::{ elaborator::{ElaborateReason, Elaborator}, hir::{ comptime::{ + InterpreterError, Value, errors::IResult, value::{ExprValue, TypedExpr}, - InterpreterError, Value, }, def_collector::dc_crate::CollectedItems, def_map::ModuleDefId, @@ -41,7 +42,6 @@ use crate::{ node_interner::{DefinitionKind, NodeInterner, TraitImplKind}, parser::{Parser, StatementOrExpressionOrLValue}, token::{Attribute, LocatedToken, Token}, - Kind, QuotedType, ResolvedGeneric, Shared, Type, TypeVariable, }; use self::builtin_helpers::{eq_item, get_array, get_ctstring, get_str, get_u8, hash_item, lex}; @@ -958,11 +958,7 @@ fn to_le_radix( None => 0, }; // The only built-ins that use these either return `[u1; N]` or `[u8; N]` - if return_type_is_bits { - Value::U1(digit != 0) - } else { - Value::U8(digit) - } + if return_type_is_bits { Value::U1(digit != 0) } else { Value::U8(digit) } }); let result_type = Type::Array( @@ -1045,11 +1041,7 @@ fn type_as_mutable_reference( location: Location, ) -> IResult { type_as(arguments, return_type, location, |typ| { - if let Type::MutableReference(typ) = typ { - Some(Value::Type(*typ)) - } else { - None - } + if let Type::MutableReference(typ) = typ { Some(Value::Type(*typ)) } else { None } }) } @@ -1060,11 +1052,7 @@ fn type_as_slice( location: Location, ) -> IResult { type_as(arguments, return_type, location, |typ| { - if let Type::Slice(slice_type) = typ { - Some(Value::Type(*slice_type)) - } else { - None - } + if let Type::Slice(slice_type) = typ { Some(Value::Type(*slice_type)) } else { None } }) } @@ -1075,11 +1063,7 @@ fn type_as_str( location: Location, ) -> IResult { type_as(arguments, return_type, location, |typ| { - if let Type::String(n) = typ { - Some(Value::Type(*n)) - } else { - None - } + if let Type::String(n) = typ { Some(Value::Type(*n)) } else { None } }) } @@ -1322,11 +1306,7 @@ fn typed_expr_get_type( let typed_expr = get_typed_expr(self_argument)?; let option_value = if let TypedExpr::ExprId(expr_id) = typed_expr { let typ = interner.id_type(expr_id); - if typ == Type::Error { - None - } else { - Some(Value::Type(typ)) - } + if typ == Type::Error { None } else { Some(Value::Type(typ)) } } else { None }; diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs index 0f0cd2f310f..e552cf0c5a2 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs @@ -12,16 +12,18 @@ use crate::hir::def_collector::dc_crate::CompilationError; use crate::lexer::Lexer; use crate::parser::{Parser, ParserError}; use crate::token::LocatedToken; +use crate::{DataType, Kind, Shared}; use crate::{ + QuotedType, Type, ast::{ BlockExpression, ExpressionKind, Ident, IntegerBitSize, LValue, Pattern, Signedness, StatementKind, UnresolvedTypeData, }, hir::{ comptime::{ + Interpreter, InterpreterError, Value, errors::IResult, value::{ExprValue, TypedExpr}, - Interpreter, InterpreterError, Value, }, def_map::ModuleId, type_check::generics::TraitGenerics, @@ -32,9 +34,7 @@ use crate::{ }, node_interner::{FuncId, NodeInterner, TraitId, TraitImplId, TypeId}, token::{SecondaryAttribute, Token, Tokens}, - QuotedType, Type, }; -use crate::{DataType, Kind, Shared}; use rustc_hash::FxHashMap as HashMap; pub(crate) fn check_argument_count( diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/foreign.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/foreign.rs index 5c1542c4045..823e0297755 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/foreign.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/foreign.rs @@ -1,28 +1,28 @@ use acvm::{ + AcirField, BlackBoxResolutionError, FieldElement, acir::BlackBoxFunc, blackbox_solver::{BigIntSolverWithId, BlackBoxFunctionSolver}, - AcirField, BlackBoxResolutionError, FieldElement, }; use bn254_blackbox_solver::Bn254BlackBoxSolver; // Currently locked to only bn254! use im::Vector; use noirc_errors::Location; use crate::{ + Type, hir::comptime::{ - errors::IResult, interpreter::builtin::builtin_helpers::to_byte_array, InterpreterError, - Value, + InterpreterError, Value, errors::IResult, + interpreter::builtin::builtin_helpers::to_byte_array, }, node_interner::NodeInterner, - Type, }; use super::{ + Interpreter, builtin::builtin_helpers::{ check_arguments, check_one_argument, check_three_arguments, check_two_arguments, get_array_map, get_bool, get_field, get_fixed_array_map, get_slice_map, get_struct_field, - get_struct_fields, get_u32, get_u64, get_u8, to_byte_slice, to_field_array, to_struct, + get_struct_fields, get_u8, get_u32, get_u64, to_byte_slice, to_field_array, to_struct, }, - Interpreter, }; impl Interpreter<'_, '_> { @@ -422,11 +422,11 @@ mod tests { use noirc_errors::Location; use strum::IntoEnumIterator; - use crate::hir::comptime::tests::with_interpreter; + use crate::Type; use crate::hir::comptime::InterpreterError::{ ArgumentCountMismatch, InvalidInComptimeContext, Unimplemented, }; - use crate::Type; + use crate::hir::comptime::tests::with_interpreter; use super::call_foreign; diff --git a/compiler/noirc_frontend/src/hir/comptime/tests.rs b/compiler/noirc_frontend/src/hir/comptime/tests.rs index 12de07f07bc..88a2bc8b52a 100644 --- a/compiler/noirc_frontend/src/hir/comptime/tests.rs +++ b/compiler/noirc_frontend/src/hir/comptime/tests.rs @@ -7,9 +7,9 @@ use fm::{FileId, FileManager}; use noirc_arena::Index; use noirc_errors::Location; +use super::Interpreter; use super::errors::InterpreterError; use super::value::Value; -use super::Interpreter; use crate::elaborator::{Elaborator, ElaboratorOptions}; use crate::hir::def_collector::dc_crate::{CompilationError, DefCollector}; use crate::hir::def_collector::dc_mod::collect_defs; diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index dd9b27c6c44..8d07669497f 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -7,6 +7,7 @@ use noirc_errors::Location; use strum_macros::Display; use crate::{ + Kind, QuotedType, Shared, Type, TypeBindings, ast::{ ArrayLiteral, BlockExpression, ConstructorExpression, Expression, ExpressionKind, Ident, IntegerBitSize, LValue, Literal, Pattern, Signedness, Statement, StatementKind, @@ -25,7 +26,6 @@ use crate::{ parser::{Item, Parser}, signed_field::SignedField, token::{LocatedToken, Token, Tokens}, - Kind, QuotedType, Shared, Type, TypeBindings, }; use rustc_hash::FxHashMap as HashMap; 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 489b1e85a21..b0c71f1ebe6 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -11,8 +11,8 @@ use crate::token::SecondaryAttribute; use crate::usage_tracker::UnusedItem; use crate::{Generics, Type}; -use crate::hir::resolution::import::{resolve_import, ImportDirective}; use crate::hir::Context; +use crate::hir::resolution::import::{ImportDirective, resolve_import}; use crate::ast::{Expression, NoirEnumeration}; use crate::node_interner::{ diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 83382e0bb6c..8ba6be4fc4b 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use std::vec; use acvm::{AcirField, FieldElement}; -use fm::{FileId, FileManager, FILE_EXTENSION}; +use fm::{FILE_EXTENSION, FileId, FileManager}; use noirc_errors::{Location, Span}; use num_bigint::BigUint; use num_traits::Num; @@ -20,13 +20,13 @@ use crate::hir::resolution::errors::ResolverError; use crate::node_interner::{ModuleAttributes, NodeInterner, ReferenceId, TypeId}; use crate::token::SecondaryAttribute; use crate::usage_tracker::{UnusedItem, UsageTracker}; +use crate::{Generics, Kind, ResolvedGeneric, Type, TypeVariable}; use crate::{ graph::CrateId, hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait}, node_interner::{FunctionModifiers, TraitId, TypeAliasId}, parser::{SortedModule, SortedSubModule}, }; -use crate::{Generics, Kind, ResolvedGeneric, Type, TypeVariable}; use super::dc_crate::ModuleAttribute; use super::dc_crate::{CollectedItems, UnresolvedEnum}; @@ -37,9 +37,9 @@ use super::{ }, errors::{DefCollectorErrorKind, DuplicateType}, }; -use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleData, ModuleId, MAIN_FUNCTION}; -use crate::hir::resolution::import::ImportDirective; use crate::hir::Context; +use crate::hir::def_map::{CrateDefMap, LocalModuleId, MAIN_FUNCTION, ModuleData, ModuleId}; +use crate::hir::resolution::import::ImportDirective; /// Given a module collect all definitions into ModuleData struct ModCollector<'a> { @@ -1324,11 +1324,7 @@ fn is_native_field(str: &str) -> bool { } else { BigUint::from_str_radix(str, 10) }; - if let Ok(big_num) = big_num { - big_num == FieldElement::modulus() - } else { - CHOSEN_FIELD == str - } + if let Ok(big_num) = big_num { big_num == FieldElement::modulus() } else { CHOSEN_FIELD == str } } type AssociatedTypes = Vec<(Ident, UnresolvedType)>; diff --git a/compiler/noirc_frontend/src/hir/def_collector/errors.rs b/compiler/noirc_frontend/src/hir/def_collector/errors.rs index 4e764daabfe..7f17b1e3043 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/errors.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/errors.rs @@ -2,7 +2,6 @@ use crate::ast::{Ident, ItemVisibility, Path, UnsupportedNumericGenericType}; use crate::hir::resolution::import::PathResolutionError; use crate::hir::type_check::generics::TraitGenerics; -use noirc_errors::FileDiagnostic; use noirc_errors::{CustomDiagnostic as Diagnostic, Location}; use thiserror::Error; @@ -56,9 +55,7 @@ pub enum DefCollectorErrorKind { ModuleAlreadyPartOfCrate { mod_name: Ident, location: Location }, #[error("Module was originally declared here")] ModuleOriginallyDefined { mod_name: Ident, location: Location }, - #[error( - "Either the type or the trait must be from the same crate as the trait implementation" - )] + #[error("Either the type or the trait must be from the same crate as the trait implementation")] TraitImplOrphaned { location: Location }, #[error("impl has stricter requirements than trait")] ImplIsStricterThanTrait { @@ -78,13 +75,9 @@ pub enum DefCollectorErrorKind { } impl DefCollectorErrorKind { - pub fn into_file_diagnostic(&self, file: fm::FileId) -> FileDiagnostic { - Diagnostic::from(self).in_file(file) - } - pub fn location(&self) -> Location { match self { - DefCollectorErrorKind::Duplicate { first_def: ident, .. } + DefCollectorErrorKind::Duplicate { second_def: ident, .. } | DefCollectorErrorKind::UnresolvedModuleDecl { mod_name: ident, .. } | DefCollectorErrorKind::CannotReexportItemWithLessVisibility { item_name: ident, @@ -167,10 +160,10 @@ impl<'a> From<&'a DefCollectorErrorKind> for Diagnostic { let second_location = second_def.0.location(); let mut diag = Diagnostic::simple_error( primary_message, - format!("First {} found here", &typ), - first_location, + format!("Second {} found here", &typ), + second_location, ); - diag.add_secondary(format!("Second {} found here", &typ), second_location); + diag.add_secondary(format!("First {} found here", &typ), first_location); diag } } diff --git a/compiler/noirc_frontend/src/hir/def_map/item_scope.rs b/compiler/noirc_frontend/src/hir/def_map/item_scope.rs index 3ca89e56bbc..bbc2f59c655 100644 --- a/compiler/noirc_frontend/src/hir/def_map/item_scope.rs +++ b/compiler/noirc_frontend/src/hir/def_map/item_scope.rs @@ -1,8 +1,8 @@ -use super::{namespace::PerNs, ModuleDefId, ModuleId}; +use super::{ModuleDefId, ModuleId, namespace::PerNs}; use crate::ast::{Ident, ItemVisibility}; use crate::node_interner::{FuncId, TraitId}; -use std::collections::{hash_map::Entry, HashMap}; +use std::collections::{HashMap, hash_map::Entry}; type Scope = HashMap, (ModuleDefId, ItemVisibility, bool /*is_prelude*/)>; @@ -50,11 +50,7 @@ impl ItemScope { let is_prelude = std::mem::replace(&mut n.get_mut().2, is_prelude); let old_ident = o.key(); - if is_prelude { - Ok(()) - } else { - Err((old_ident.clone(), name)) - } + if is_prelude { Ok(()) } else { Err((old_ident.clone(), name)) } } else { trait_hashmap.insert(trait_id, (mod_def, visibility, is_prelude)); Ok(()) diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 4ccacc8c3b5..5377ee7d42a 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -1,7 +1,7 @@ use crate::elaborator::FrontendOptions; use crate::graph::{CrateGraph, CrateId}; -use crate::hir::def_collector::dc_crate::{CompilationError, DefCollector}; use crate::hir::Context; +use crate::hir::def_collector::dc_crate::{CompilationError, DefCollector}; use crate::node_interner::{FuncId, GlobalId, NodeInterner, TypeId}; use crate::parse_program; use crate::parser::{ParsedModule, ParserError}; diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index 1c4e1f6e65c..8f2c3c5f867 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -14,7 +14,7 @@ use crate::parser::ParserError; use crate::usage_tracker::UsageTracker; use crate::{Generics, Kind, ParsedModule, ResolvedGeneric, TypeVariable}; use def_collector::dc_crate::CompilationError; -use def_map::{fully_qualified_module_path, Contract, CrateDefMap}; +use def_map::{Contract, CrateDefMap, fully_qualified_module_path}; use fm::{FileId, FileManager}; use iter_extended::vecmap; use noirc_errors::Location; @@ -139,11 +139,7 @@ impl Context<'_, '_> { let parent = def_map.get_module_path_with_separator(module_id.local_id.0, module.parent, "::"); - if parent.is_empty() { - name.into() - } else { - format!("{parent}::{name}") - } + if parent.is_empty() { name.into() } else { format!("{parent}::{name}") } } /// Returns a fully-qualified path to the given [StructId] from the given [CrateId]. This function also diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index cee6bd3b913..bc1c519ed5d 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -1,9 +1,10 @@ use acvm::FieldElement; pub use noirc_errors::Span; -use noirc_errors::{CustomDiagnostic as Diagnostic, FileDiagnostic, Location}; +use noirc_errors::{CustomDiagnostic as Diagnostic, Location}; use thiserror::Error; use crate::{ + Kind, Type, ast::{Ident, UnsupportedNumericGenericType}, hir::{ comptime::{InterpreterError, Value}, @@ -11,7 +12,6 @@ use crate::{ }, parser::ParserError, usage_tracker::UnusedItem, - Kind, Type, }; use super::import::PathResolutionError; @@ -86,9 +86,7 @@ pub enum ResolverError { "Usage of the `#[foreign]` or `#[builtin]` function attributes are not allowed outside of the Noir standard library" )] LowLevelFunctionOutsideOfStdlib { ident: Ident }, - #[error( - "Usage of the `#[oracle]` function attribute is only valid on unconstrained functions" - )] + #[error("Usage of the `#[oracle]` function attribute is only valid on unconstrained functions")] OracleMarkedAsConstrained { ident: Ident }, #[error("Oracle functions cannot be called directly from constrained functions")] UnconstrainedOracleReturnToConstrained { location: Location }, @@ -107,7 +105,11 @@ pub enum ResolverError { #[error("Only `comptime` globals can be mutable")] MutableGlobal { location: Location }, #[error("Globals must have a specified type")] - UnspecifiedGlobalType { location: Location, expected_type: Type }, + UnspecifiedGlobalType { + pattern_location: Location, + expr_location: Location, + expected_type: Type, + }, #[error("Global failed to evaluate")] UnevaluatedGlobalType { location: Location }, #[error("Globals used in a type position must be non-negative")] @@ -128,8 +130,6 @@ pub enum ResolverError { ArrayLengthInterpreter { error: InterpreterError }, #[error("The unquote operator '$' can only be used within a quote expression")] UnquoteUsedOutsideQuote { location: Location }, - #[error("\"as trait path\" not yet implemented")] - AsTraitPathNotYetImplemented { location: Location }, #[error("Invalid syntax in macro call")] InvalidSyntaxInMacroCall { location: Location }, #[error("Macros must be comptime functions")] @@ -168,7 +168,7 @@ pub enum ResolverError { AttributeFunctionIsNotAPath { function: String, location: Location }, #[error("Attribute function `{name}` is not in scope")] AttributeFunctionNotInScope { name: String, location: Location }, - #[error("The trait `{missing_trait}` is not implemented for `{type_missing_trait}")] + #[error("The trait `{missing_trait}` is not implemented for `{type_missing_trait}`")] TraitNotImplemented { impl_trait: String, missing_trait: String, @@ -190,16 +190,14 @@ pub enum ResolverError { TypeUnsupportedInMatch { typ: Type, location: Location }, #[error("Expected a struct, enum, or literal value in pattern, but found a {item}")] UnexpectedItemInPattern { location: Location, item: &'static str }, + #[error("Trait `{trait_name}` doesn't have a method named `{method_name}`")] + NoSuchMethodInTrait { trait_name: String, method_name: String, location: Location }, } impl ResolverError { - pub fn into_file_diagnostic(&self, file: fm::FileId) -> FileDiagnostic { - Diagnostic::from(self).in_file(file) - } - pub fn location(&self) -> Location { match self { - ResolverError::DuplicateDefinition { first_location: location, .. } + ResolverError::DuplicateDefinition { second_location: location, .. } | ResolverError::UnconditionalRecursion { location, .. } | ResolverError::PathIsNotIdent { location } | ResolverError::Expected { location, .. } @@ -233,7 +231,7 @@ impl ResolverError { | ResolverError::WhileInConstrainedFn { location } | ResolverError::JumpOutsideLoop { location, .. } | ResolverError::MutableGlobal { location } - | ResolverError::UnspecifiedGlobalType { location, .. } + | ResolverError::UnspecifiedGlobalType { pattern_location: location, .. } | ResolverError::UnevaluatedGlobalType { location } | ResolverError::NegativeGlobalType { location, .. } | ResolverError::NonIntegralGlobalType { location, .. } @@ -241,7 +239,6 @@ impl ResolverError { | ResolverError::SelfReferentialType { location } | ResolverError::NumericGenericUsedForType { location, .. } | ResolverError::UnquoteUsedOutsideQuote { location } - | ResolverError::AsTraitPathNotYetImplemented { location } | ResolverError::InvalidSyntaxInMacroCall { location } | ResolverError::MacroIsNotComptime { location } | ResolverError::NonFunctionInAnnotation { location } @@ -257,6 +254,7 @@ impl ResolverError { | ResolverError::NonIntegerGlobalUsedInPattern { location, .. } | ResolverError::TypeUnsupportedInMatch { location, .. } | ResolverError::UnexpectedItemInPattern { location, .. } + | ResolverError::NoSuchMethodInTrait { location, .. } | ResolverError::VariableAlreadyDefinedInPattern { new_location: location, .. } => { *location } @@ -292,10 +290,10 @@ impl<'a> From<&'a ResolverError> for Diagnostic { ResolverError::DuplicateDefinition { name, first_location, second_location} => { let mut diag = Diagnostic::simple_error( format!("duplicate definitions of {name} found"), - "first definition found here".to_string(), - *first_location, + "second definition found here".to_string(), + *second_location, ); - diag.add_secondary("second definition found here".to_string(), *second_location); + diag.add_secondary("first definition found here".to_string(), *first_location); diag } ResolverError::UnusedVariable { ident } => { @@ -567,12 +565,14 @@ impl<'a> From<&'a ResolverError> for Diagnostic { *location, ) }, - ResolverError::UnspecifiedGlobalType { location, expected_type } => { - Diagnostic::simple_error( + ResolverError::UnspecifiedGlobalType { pattern_location, expr_location, expected_type } => { + let mut diagnostic = Diagnostic::simple_error( "Globals must have a specified type".to_string(), - format!("Inferred type is `{expected_type}`"), - *location, - ) + String::new(), + *pattern_location, + ); + diagnostic.add_secondary(format!("Inferred type is `{expected_type}`"), *expr_location); + diagnostic }, ResolverError::UnevaluatedGlobalType { location } => { Diagnostic::simple_error( @@ -648,13 +648,6 @@ impl<'a> From<&'a ResolverError> for Diagnostic { *location, ) }, - ResolverError::AsTraitPathNotYetImplemented { location } => { - Diagnostic::simple_error( - "\"as trait path\" not yet implemented".into(), - "".into(), - *location, - ) - }, ResolverError::InvalidSyntaxInMacroCall { location } => { Diagnostic::simple_error( "Invalid syntax in macro call".into(), @@ -764,9 +757,9 @@ impl<'a> From<&'a ResolverError> for Diagnostic { ResolverError::TraitNotImplemented { impl_trait, missing_trait: the_trait, type_missing_trait: typ, location, missing_trait_location} => { let mut diagnostic = Diagnostic::simple_error( format!("The trait bound `{typ}: {the_trait}` is not satisfied"), - format!("The trait `{the_trait}` is not implemented for `{typ}") + format!("The trait `{the_trait}` is not implemented for `{typ}`") , *location); - diagnostic.add_secondary(format!("required by this bound in `{impl_trait}"), *missing_trait_location); + diagnostic.add_secondary(format!("required by this bound in `{impl_trait}`"), *missing_trait_location); diagnostic }, ResolverError::LoopNotYetSupported { location } => { @@ -812,6 +805,13 @@ impl<'a> From<&'a ResolverError> for Diagnostic { *location, ) }, + ResolverError::NoSuchMethodInTrait { trait_name, method_name, location } => { + Diagnostic::simple_error( + format!("Trait `{trait_name}` has no method named `{method_name}`"), + String::new(), + *location, + ) + }, } } } diff --git a/compiler/noirc_frontend/src/hir/resolution/visibility.rs b/compiler/noirc_frontend/src/hir/resolution/visibility.rs index 1ae0037bc7d..84badde9d35 100644 --- a/compiler/noirc_frontend/src/hir/resolution/visibility.rs +++ b/compiler/noirc_frontend/src/hir/resolution/visibility.rs @@ -1,6 +1,6 @@ +use crate::Type; use crate::graph::CrateId; use crate::node_interner::{FuncId, NodeInterner, TraitId, TypeId}; -use crate::Type; use std::collections::BTreeMap; diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index 4aa6adae029..9198182312d 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -63,7 +63,7 @@ pub enum TypeCheckError { #[error("Expected type {expected} is not the same as {actual}")] TypeMismatchWithSource { expected: Type, actual: Type, location: Location, source: Source }, #[error("Expected type {expected_kind:?} is not the same as {expr_kind:?}")] - TypeKindMismatch { expected_kind: String, expr_kind: String, expr_location: Location }, + TypeKindMismatch { expected_kind: Kind, expr_kind: Kind, expr_location: Location }, #[error("Evaluating {to} resulted in {to_value}, but {from_value} was expected")] TypeCanonicalizationMismatch { to: Type, @@ -377,11 +377,37 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic { ) } TypeCheckError::TypeKindMismatch { expected_kind, expr_kind, expr_location } => { - Diagnostic::simple_error( - format!("Expected kind {expected_kind}, found kind {expr_kind}"), - String::new(), - *expr_location, - ) + // Try to improve the error message for some kind combinations + match (expected_kind, expr_kind) { + (Kind::Normal, Kind::Numeric(_)) => { + Diagnostic::simple_error( + "Expected type, found numeric generic".into(), + "not a type".into(), + *expr_location, + ) + } + (Kind::Numeric(typ), Kind::Normal) => { + Diagnostic::simple_error( + "Type provided when a numeric generic was expected".into(), + format!("the numeric generic is not of type `{typ}`"), + *expr_location, + ) + } + (Kind::Numeric(expected_type), Kind::Numeric(found_type)) => { + Diagnostic::simple_error( + format!("The numeric generic is not of type `{expected_type}`"), + format!("expected `{expected_type}`, found `{found_type}`"), + *expr_location, + ) + } + _ => { + Diagnostic::simple_error( + format!("Expected kind {expected_kind}, found kind {expr_kind}"), + String::new(), + *expr_location, + ) + } + } } TypeCheckError::TypeCanonicalizationMismatch { to, from, to_value, from_value, location } => { Diagnostic::simple_error( @@ -556,7 +582,7 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic { Diagnostic::simple_error(message, String::new(), *location) } - TypeCheckError::CallDeprecated { location, ref note, .. } => { + TypeCheckError::CallDeprecated { location, note, .. } => { let primary_message = error.to_string(); let secondary_message = note.clone().unwrap_or_default(); @@ -664,15 +690,15 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic { impl<'a> From<&'a NoMatchingImplFoundError> for Diagnostic { fn from(error: &'a NoMatchingImplFoundError) -> Self { let constraints = &error.constraints; - let span = error.location; + let location = error.location; assert!(!constraints.is_empty()); let msg = format!("No matching impl found for `{}: {}`", constraints[0].0, constraints[0].1); - let mut diagnostic = Diagnostic::from_message(&msg); + let mut diagnostic = Diagnostic::from_message(&msg, location.file); let secondary = format!("No impl for `{}: {}`", constraints[0].0, constraints[0].1); - diagnostic.add_secondary(secondary, span); + diagnostic.add_secondary(secondary, location); // These must be notes since secondaries are unordered for (typ, trait_name) in &constraints[1..] { diff --git a/compiler/noirc_frontend/src/hir/type_check/generics.rs b/compiler/noirc_frontend/src/hir/type_check/generics.rs index f823b495040..29baee8c30a 100644 --- a/compiler/noirc_frontend/src/hir/type_check/generics.rs +++ b/compiler/noirc_frontend/src/hir/type_check/generics.rs @@ -3,9 +3,9 @@ use std::cell::Ref; use iter_extended::vecmap; use crate::{ + DataType, ResolvedGeneric, Type, hir_def::traits::NamedType, node_interner::{FuncId, NodeInterner, TraitId, TypeAliasId}, - DataType, ResolvedGeneric, Type, }; /// Represents something that can be generic over type variables diff --git a/compiler/noirc_frontend/src/hir_def/expr.rs b/compiler/noirc_frontend/src/hir_def/expr.rs index ab4ad2ac2a8..0076cab8de5 100644 --- a/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/compiler/noirc_frontend/src/hir_def/expr.rs @@ -1,6 +1,7 @@ use fm::FileId; use noirc_errors::Location; +use crate::Shared; use crate::ast::{BinaryOp, BinaryOpKind, Ident, UnaryOp}; use crate::hir::type_check::generics::TraitGenerics; use crate::node_interner::{ @@ -8,7 +9,6 @@ use crate::node_interner::{ }; use crate::signed_field::SignedField; use crate::token::{FmtStrFragment, Tokens}; -use crate::Shared; use super::stmt::HirPattern; use super::traits::{ResolvedTraitBound, TraitConstraint}; diff --git a/compiler/noirc_frontend/src/hir_def/stmt.rs b/compiler/noirc_frontend/src/hir_def/stmt.rs index b0e00434903..21db5971bf0 100644 --- a/compiler/noirc_frontend/src/hir_def/stmt.rs +++ b/compiler/noirc_frontend/src/hir_def/stmt.rs @@ -1,8 +1,8 @@ use super::expr::HirIdent; +use crate::Type; use crate::ast::Ident; use crate::node_interner::{ExprId, StmtId}; use crate::token::SecondaryAttribute; -use crate::Type; use noirc_errors::{Location, Span}; /// A HirStatement is the result of performing name resolution on diff --git a/compiler/noirc_frontend/src/hir_def/traits.rs b/compiler/noirc_frontend/src/hir_def/traits.rs index ea962a7bdfd..a344b276913 100644 --- a/compiler/noirc_frontend/src/hir_def/traits.rs +++ b/compiler/noirc_frontend/src/hir_def/traits.rs @@ -1,13 +1,13 @@ use iter_extended::vecmap; use rustc_hash::FxHashMap as HashMap; +use crate::ResolvedGeneric; use crate::ast::{Ident, ItemVisibility, NoirFunction}; use crate::hir::type_check::generics::TraitGenerics; -use crate::ResolvedGeneric; use crate::{ + Generics, Type, TypeBindings, TypeVariable, graph::CrateId, node_interner::{FuncId, TraitId, TraitMethodId}, - Generics, Type, TypeBindings, TypeVariable, }; use fm::FileId; use noirc_errors::{Location, Span}; diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 3a0e1d9089c..e7960c59521 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -12,7 +12,7 @@ use acvm::{AcirField, FieldElement}; use crate::{ ast::{IntegerBitSize, ItemVisibility}, - hir::type_check::{generics::TraitGenerics, TypeCheckError}, + hir::type_check::{TypeCheckError, generics::TraitGenerics}, node_interner::{ExprId, NodeInterner, TraitId, TypeAliasId}, }; use iter_extended::vecmap; @@ -249,11 +249,7 @@ impl Kind { } pub(crate) fn unify(&self, other: &Kind) -> Result<(), UnificationError> { - if self.unifies(other) { - Ok(()) - } else { - Err(UnificationError) - } + if self.unifies(other) { Ok(()) } else { Err(UnificationError) } } /// Returns the default type this type variable should be bound to if it is still unbound @@ -862,8 +858,8 @@ impl TypeVariable { ) -> Result<(), TypeCheckError> { if !binding.kind().unifies(kind) { return Err(TypeCheckError::TypeKindMismatch { - expected_kind: format!("{}", kind), - expr_kind: format!("{}", binding.kind()), + expected_kind: kind.clone(), + expr_kind: binding.kind(), expr_location: location, }); } @@ -1058,11 +1054,7 @@ impl std::fmt::Display for Type { let this = self.canonicalize_checked(); // Prevent infinite recursion - if this != *self { - write!(f, "{this}") - } else { - write!(f, "({lhs} {op} {rhs})") - } + if this != *self { write!(f, "{this}") } else { write!(f, "({lhs} {op} {rhs})") } } } } @@ -1466,8 +1458,8 @@ impl Type { Type::NamedGeneric(var, _) => var.kind(), Type::Constant(_, kind) => kind.clone(), Type::TypeVariable(var) => match &*var.borrow() { - TypeBinding::Bound(ref typ) => typ.kind(), - TypeBinding::Unbound(_, ref type_var_kind) => type_var_kind.clone(), + TypeBinding::Bound(typ) => typ.kind(), + TypeBinding::Unbound(_, type_var_kind) => type_var_kind.clone(), }, Type::InfixExpr(lhs, _op, rhs, _) => lhs.infix_kind(rhs), Type::Alias(def, generics) => def.borrow().get_type(generics).kind(), @@ -1495,11 +1487,7 @@ impl Type { fn infix_kind(&self, other: &Self) -> Kind { let self_kind = self.kind(); let other_kind = other.kind(); - if self_kind.unifies(&other_kind) { - self_kind - } else { - Kind::numeric(Type::Error) - } + if self_kind.unifies(&other_kind) { self_kind } else { Kind::numeric(Type::Error) } } /// Creates an `InfixExpr`. @@ -1667,8 +1655,8 @@ impl Type { typ.try_bind_to_polymorphic_int(var, bindings, only_integer) } // Avoid infinitely recursive bindings - TypeBinding::Unbound(ref id, _) if *id == target_id => Ok(()), - TypeBinding::Unbound(ref new_target_id, Kind::IntegerOrField) => { + TypeBinding::Unbound(id, _) if *id == target_id => Ok(()), + TypeBinding::Unbound(new_target_id, Kind::IntegerOrField) => { let type_var_kind = Kind::IntegerOrField; if only_integer { let var_clone = var.clone(); @@ -1691,7 +1679,7 @@ impl Type { bindings.insert(target_id, (var.clone(), Kind::Integer, this.clone())); Ok(()) } - TypeBinding::Unbound(new_target_id, ref type_var_kind) => { + TypeBinding::Unbound(new_target_id, type_var_kind) => { let var_clone = var.clone(); // Bind to the most specific type variable kind let clone_kind = @@ -2160,8 +2148,8 @@ impl Type { kind.ensure_value_fits(x, location) } else { Err(TypeCheckError::TypeKindMismatch { - expected_kind: format!("{}", constant_kind), - expr_kind: format!("{}", kind), + expected_kind: constant_kind, + expr_kind: kind.clone(), expr_location: location, }) } @@ -2182,8 +2170,8 @@ impl Type { op.function(lhs_value, rhs_value, &infix_kind, location) } else { Err(TypeCheckError::TypeKindMismatch { - expected_kind: format!("{}", kind), - expr_kind: format!("{}", infix_kind), + expected_kind: kind.clone(), + expr_kind: infix_kind, expr_location: location, }) } @@ -2929,7 +2917,7 @@ impl From<&Type> for PrintableType { Type::Error => unreachable!(), Type::Unit => PrintableType::Unit, Type::Constant(_, _) => unreachable!(), - Type::DataType(def, ref args) => { + Type::DataType(def, args) => { let data_type = def.borrow(); let name = data_type.name.to_string(); diff --git a/compiler/noirc_frontend/src/lexer/lexer.rs b/compiler/noirc_frontend/src/lexer/lexer.rs index 0777c235ad9..630f192c109 100644 --- a/compiler/noirc_frontend/src/lexer/lexer.rs +++ b/compiler/noirc_frontend/src/lexer/lexer.rs @@ -665,11 +665,7 @@ impl<'a> Lexer<'a> { } fn eat_format_string_or_alpha_numeric(&mut self) -> SpannedTokenResult { - if self.peek_char_is('"') { - self.eat_fmt_string() - } else { - self.eat_alpha_numeric('f') - } + if self.peek_char_is('"') { self.eat_fmt_string() } else { self.eat_alpha_numeric('f') } } fn eat_raw_string(&mut self) -> SpannedTokenResult { @@ -883,11 +879,7 @@ impl Iterator for Lexer<'_> { type Item = LocatedTokenResult; fn next(&mut self) -> Option { - if self.done { - None - } else { - Some(self.next_token()) - } + if self.done { None } else { Some(self.next_token()) } } } diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index 0b4a4bad278..7367489f625 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -255,18 +255,18 @@ pub enum Token { pub fn token_to_borrowed_token(token: &Token) -> BorrowedToken<'_> { match token { - Token::Ident(ref s) => BorrowedToken::Ident(s), + Token::Ident(s) => BorrowedToken::Ident(s), Token::Int(n) => BorrowedToken::Int(*n), Token::Bool(b) => BorrowedToken::Bool(*b), - Token::Str(ref b) => BorrowedToken::Str(b), - Token::FmtStr(ref b, length) => BorrowedToken::FmtStr(b, *length), - Token::RawStr(ref b, hashes) => BorrowedToken::RawStr(b, *hashes), + Token::Str(b) => BorrowedToken::Str(b), + Token::FmtStr(b, length) => BorrowedToken::FmtStr(b, *length), + Token::RawStr(b, hashes) => BorrowedToken::RawStr(b, *hashes), Token::Keyword(k) => BorrowedToken::Keyword(*k), Token::AttributeStart { is_inner, is_tag } => { BorrowedToken::AttributeStart { is_inner: *is_inner, is_tag: *is_tag } } - Token::LineComment(ref s, _style) => BorrowedToken::LineComment(s, *_style), - Token::BlockComment(ref s, _style) => BorrowedToken::BlockComment(s, *_style), + Token::LineComment(s, _style) => BorrowedToken::LineComment(s, *_style), + Token::BlockComment(s, _style) => BorrowedToken::BlockComment(s, *_style), Token::Quote(stream) => BorrowedToken::Quote(stream), Token::QuotedType(id) => BorrowedToken::QuotedType(*id), Token::InternedExpr(id) => BorrowedToken::InternedExpression(*id), @@ -274,7 +274,7 @@ pub fn token_to_borrowed_token(token: &Token) -> BorrowedToken<'_> { Token::InternedLValue(id) => BorrowedToken::InternedLValue(*id), Token::InternedUnresolvedTypeData(id) => BorrowedToken::InternedUnresolvedTypeData(*id), Token::InternedPattern(id) => BorrowedToken::InternedPattern(*id), - Token::IntType(ref i) => BorrowedToken::IntType(i.clone()), + Token::IntType(i) => BorrowedToken::IntType(i.clone()), Token::Less => BorrowedToken::Less, Token::LessEqual => BorrowedToken::LessEqual, Token::Greater => BorrowedToken::Greater, @@ -312,7 +312,7 @@ pub fn token_to_borrowed_token(token: &Token) -> BorrowedToken<'_> { Token::DollarSign => BorrowedToken::DollarSign, Token::EOF => BorrowedToken::EOF, Token::Invalid(c) => BorrowedToken::Invalid(*c), - Token::Whitespace(ref s) => BorrowedToken::Whitespace(s), + Token::Whitespace(s) => BorrowedToken::Whitespace(s), Token::UnquoteMarker(id) => BorrowedToken::UnquoteMarker(*id), } } @@ -578,7 +578,7 @@ pub enum TokenKind { impl fmt::Display for TokenKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - TokenKind::Token(ref tok) => write!(f, "{tok}"), + TokenKind::Token(tok) => write!(f, "{tok}"), TokenKind::Ident => write!(f, "identifier"), TokenKind::Literal => write!(f, "literal"), TokenKind::Keyword => write!(f, "keyword"), @@ -926,9 +926,9 @@ impl fmt::Display for FunctionAttribute { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { FunctionAttribute::Test(scope) => write!(f, "#[test{scope}]"), - FunctionAttribute::Foreign(ref k) => write!(f, "#[foreign({k})]"), - FunctionAttribute::Builtin(ref k) => write!(f, "#[builtin({k})]"), - FunctionAttribute::Oracle(ref k) => write!(f, "#[oracle({k})]"), + FunctionAttribute::Foreign(k) => write!(f, "#[foreign({k})]"), + FunctionAttribute::Builtin(k) => write!(f, "#[builtin({k})]"), + FunctionAttribute::Oracle(k) => write!(f, "#[oracle({k})]"), FunctionAttribute::Fold => write!(f, "#[fold]"), FunctionAttribute::NoPredicates => write!(f, "#[no_predicates]"), FunctionAttribute::InlineAlways => write!(f, "#[inline_always]"), @@ -1001,18 +1001,18 @@ impl SecondaryAttribute { pub(crate) fn contents(&self) -> String { match self { SecondaryAttribute::Deprecated(None) => "deprecated".to_string(), - SecondaryAttribute::Deprecated(Some(ref note)) => { + SecondaryAttribute::Deprecated(Some(note)) => { format!("deprecated({note:?})") } - SecondaryAttribute::Tag(ref attribute) => format!("'{}", attribute.contents), - SecondaryAttribute::Meta(ref meta) => meta.to_string(), + SecondaryAttribute::Tag(attribute) => format!("'{}", attribute.contents), + SecondaryAttribute::Meta(meta) => meta.to_string(), SecondaryAttribute::ContractLibraryMethod => "contract_library_method".to_string(), SecondaryAttribute::Export => "export".to_string(), - SecondaryAttribute::Field(ref k) => format!("field({k})"), - SecondaryAttribute::Abi(ref k) => format!("abi({k})"), + SecondaryAttribute::Field(k) => format!("field({k})"), + SecondaryAttribute::Abi(k) => format!("abi({k})"), SecondaryAttribute::Varargs => "varargs".to_string(), SecondaryAttribute::UseCallersScope => "use_callers_scope".to_string(), - SecondaryAttribute::Allow(ref k) => format!("allow({k})"), + SecondaryAttribute::Allow(k) => format!("allow({k})"), } } } @@ -1055,11 +1055,7 @@ impl CustomAttribute { fn name(&self) -> Option { let mut lexer = Lexer::new_with_dummy_file(&self.contents); let token = lexer.next()?.ok()?; - if let Token::Ident(ident) = token.into_token() { - Some(ident) - } else { - None - } + if let Token::Ident(ident) = token.into_token() { Some(ident) } else { None } } } diff --git a/compiler/noirc_frontend/src/lib.rs b/compiler/noirc_frontend/src/lib.rs index a6f57b84d6f..88a32b2717c 100644 --- a/compiler/noirc_frontend/src/lib.rs +++ b/compiler/noirc_frontend/src/lib.rs @@ -32,7 +32,7 @@ pub mod hir_def; pub use lexer::token; // Parser API -pub use parser::{parse_program, parse_program_with_dummy_file, ParsedModule}; +pub use parser::{ParsedModule, parse_program, parse_program_with_dummy_file}; // Type API pub use hir_def::types::*; diff --git a/compiler/noirc_frontend/src/monomorphization/ast.rs b/compiler/noirc_frontend/src/monomorphization/ast.rs index 3d4062f0681..da86a466fdb 100644 --- a/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -2,8 +2,8 @@ use std::{collections::BTreeMap, fmt::Display}; use iter_extended::vecmap; use noirc_errors::{ - debug_info::{DebugFunctions, DebugTypes, DebugVariables}, Location, + debug_info::{DebugFunctions, DebugTypes, DebugVariables}, }; use crate::{ diff --git a/compiler/noirc_frontend/src/monomorphization/debug.rs b/compiler/noirc_frontend/src/monomorphization/debug.rs index df2a0ada959..680e7882811 100644 --- a/compiler/noirc_frontend/src/monomorphization/debug.rs +++ b/compiler/noirc_frontend/src/monomorphization/debug.rs @@ -1,7 +1,7 @@ use acvm::acir::AcirField; use iter_extended::vecmap; -use noirc_errors::debug_info::DebugVarId; use noirc_errors::Location; +use noirc_errors::debug_info::DebugVarId; use noirc_printable_type::PrintableType; use crate::debug::{SourceFieldId, SourceVarId}; diff --git a/compiler/noirc_frontend/src/monomorphization/errors.rs b/compiler/noirc_frontend/src/monomorphization/errors.rs index 86df6260ad3..93a12a46591 100644 --- a/compiler/noirc_frontend/src/monomorphization/errors.rs +++ b/compiler/noirc_frontend/src/monomorphization/errors.rs @@ -1,8 +1,8 @@ -use noirc_errors::{CustomDiagnostic, FileDiagnostic, Location}; +use noirc_errors::{CustomDiagnostic, Location}; use crate::{ - hir::{comptime::InterpreterError, type_check::TypeCheckError}, Type, + hir::{comptime::InterpreterError, type_check::TypeCheckError}, }; #[derive(Debug)] @@ -34,18 +34,9 @@ impl MonomorphizationError { } } -impl From for FileDiagnostic { - fn from(error: MonomorphizationError) -> FileDiagnostic { - let location = error.location(); - let call_stack = vec![location]; - let diagnostic = error.into_diagnostic(); - diagnostic.with_call_stack(call_stack).in_file(location.file) - } -} - -impl MonomorphizationError { - fn into_diagnostic(self) -> CustomDiagnostic { - let message = match &self { +impl From for CustomDiagnostic { + fn from(error: MonomorphizationError) -> CustomDiagnostic { + let message = match &error { MonomorphizationError::UnknownArrayLength { length, err, .. } => { format!("Could not determine array length `{length}`, encountered error: `{err}`") } @@ -78,7 +69,7 @@ impl MonomorphizationError { } }; - let location = self.location(); + let location = error.location(); CustomDiagnostic::simple_error(message, String::new(), location) } } diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 91132fb13f8..62ed1ef2e68 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -15,6 +15,7 @@ use crate::node_interner::{ExprId, GlobalValue, ImplSearchErrorKind}; use crate::signed_field::SignedField; use crate::token::FmtStrFragment; use crate::{ + Kind, Type, TypeBinding, TypeBindings, debug::DebugInstrumenter, hir_def::{ expr::*, @@ -23,9 +24,8 @@ use crate::{ types, }, node_interner::{self, DefinitionKind, NodeInterner, StmtId, TraitImplKind, TraitMethodId}, - Kind, Type, TypeBinding, TypeBindings, }; -use acvm::{acir::AcirField, FieldElement}; +use acvm::{FieldElement, acir::AcirField}; use ast::{GlobalId, While}; use fxhash::FxHashMap as HashMap; use iter_extended::{btree_map, try_vecmap, vecmap}; @@ -1182,7 +1182,7 @@ impl<'interner> Monomorphizer<'interner> { unreachable!("All TraitAsType should be replaced before calling convert_type"); } HirType::NamedGeneric(binding, _) => { - if let TypeBinding::Bound(ref binding) = &*binding.borrow() { + if let TypeBinding::Bound(binding) = &*binding.borrow() { return Self::convert_type(binding, location); } @@ -1198,12 +1198,12 @@ impl<'interner> Monomorphizer<'interner> { Self::convert_type(to, location)? } - HirType::TypeVariable(ref binding) => { + HirType::TypeVariable(binding) => { let type_var_kind = match &*binding.borrow() { - TypeBinding::Bound(ref binding) => { + TypeBinding::Bound(binding) => { return Self::convert_type(binding, location); } - TypeBinding::Unbound(_, ref type_var_kind) => type_var_kind.clone(), + TypeBinding::Unbound(_, type_var_kind) => type_var_kind.clone(), }; // Default any remaining unbound type variables. @@ -1328,18 +1328,18 @@ impl<'interner> Monomorphizer<'interner> { HirType::Array(_length, element) => Self::check_type(element.as_ref(), location), HirType::Slice(element) => Self::check_type(element.as_ref(), location), HirType::NamedGeneric(binding, _) => { - if let TypeBinding::Bound(ref binding) = &*binding.borrow() { + if let TypeBinding::Bound(binding) = &*binding.borrow() { return Self::check_type(binding, location); } Ok(()) } - HirType::TypeVariable(ref binding) => { + HirType::TypeVariable(binding) => { let type_var_kind = match &*binding.borrow() { TypeBinding::Bound(binding) => { return Self::check_type(binding, location); } - TypeBinding::Unbound(_, ref type_var_kind) => type_var_kind.clone(), + TypeBinding::Unbound(_, type_var_kind) => type_var_kind.clone(), }; // Default any remaining unbound type variables. diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 250d3f752ac..e599b99b3fd 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -13,6 +13,7 @@ use petgraph::prelude::DiGraph; use petgraph::prelude::NodeIndex as PetGraphIndex; use rustc_hash::FxHashMap as HashMap; +use crate::QuotedType; use crate::ast::{ ExpressionKind, Ident, LValue, Pattern, StatementKind, UnaryOp, UnresolvedTypeData, }; @@ -26,8 +27,9 @@ use crate::hir::type_check::generics::TraitGenerics; use crate::hir_def::traits::NamedType; use crate::hir_def::traits::ResolvedTraitBound; use crate::locations::AutoImportEntry; -use crate::QuotedType; +use crate::GenericTypeVars; +use crate::Generics; use crate::ast::{BinaryOpKind, FunctionDefinition, ItemVisibility}; use crate::hir::resolution::errors::ResolverError; use crate::hir_def::expr::HirIdent; @@ -42,8 +44,6 @@ use crate::hir_def::{ }; use crate::locations::LocationIndices; use crate::token::{Attributes, SecondaryAttribute}; -use crate::GenericTypeVars; -use crate::Generics; use crate::{Shared, TypeAlias, TypeBindings, TypeVariable, TypeVariableId}; /// An arbitrary number to limit the recursion depth when searching for trait impls. @@ -725,6 +725,15 @@ impl NodeInterner { ExprId(self.nodes.insert(Node::Expression(expr))) } + /// Intern an expression with everything needed for it (location & Type) + /// instead of requiring they be pushed later. + pub fn push_expr_full(&mut self, expr: HirExpression, location: Location, typ: Type) -> ExprId { + let id = self.push_expr(expr); + self.push_expr_location(id, location); + self.push_expr_type(id, typ); + id + } + /// Stores the span for an interned expression. pub fn push_expr_location(&mut self, expr_id: ExprId, location: Location) { self.id_to_location.insert(expr_id.into(), location); @@ -756,7 +765,7 @@ impl NodeInterner { id: type_id, name: unresolved_trait.trait_def.name.clone(), crate_id: unresolved_trait.crate_id, - location: unresolved_trait.trait_def.location, + location: unresolved_trait.trait_def.name.location(), generics, visibility: ItemVisibility::Private, self_type_typevar: TypeVariable::unbound(self.next_type_variable_id(), Kind::Normal), diff --git a/compiler/noirc_frontend/src/parser/mod.rs b/compiler/noirc_frontend/src/parser/mod.rs index 533e844b75c..0cecbe0814a 100644 --- a/compiler/noirc_frontend/src/parser/mod.rs +++ b/compiler/noirc_frontend/src/parser/mod.rs @@ -22,7 +22,7 @@ pub use errors::ParserError; pub use errors::ParserErrorReason; use noirc_errors::Location; pub use parser::{ - parse_program, parse_program_with_dummy_file, Parser, StatementOrExpressionOrLValue, + Parser, StatementOrExpressionOrLValue, parse_program, parse_program_with_dummy_file, }; #[derive(Clone, Default)] diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index fee970dc7b0..a5ea2ea5fe9 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -5,11 +5,11 @@ use noirc_errors::{Location, Span}; use crate::{ ast::{Ident, ItemVisibility}, - lexer::{lexer::LocatedTokenResult, Lexer}, + lexer::{Lexer, lexer::LocatedTokenResult}, token::{FmtStrFragment, IntType, Keyword, LocatedToken, Token, TokenKind, Tokens}, }; -use super::{labels::ParsingRuleLabel, ParsedModule, ParserError, ParserErrorReason}; +use super::{ParsedModule, ParserError, ParserErrorReason, labels::ParsingRuleLabel}; mod arguments; mod attributes; @@ -172,11 +172,7 @@ impl<'a> Parser<'a> { } let all_warnings = self.errors.iter().all(|error| error.is_warning()); - if all_warnings { - Ok((item, self.errors)) - } else { - Err(self.errors) - } + if all_warnings { Ok((item, self.errors)) } else { Err(self.errors) } } /// Bumps this parser by one token. Returns the token that was previously the "current" token. @@ -212,6 +208,9 @@ impl<'a> Parser<'a> { match self.tokens.next() { Some(Ok(token)) => match token.token() { Token::LineComment(comment, None) | Token::BlockComment(comment, None) => { + if !last_comments.is_empty() { + last_comments.push('\n'); + } last_comments.push_str(comment); continue; } @@ -226,11 +225,7 @@ impl<'a> Parser<'a> { } fn eat_kind(&mut self, kind: TokenKind) -> Option { - if self.token.kind() == kind { - Some(self.bump()) - } else { - None - } + if self.token.kind() == kind { Some(self.bump()) } else { None } } fn eat_keyword(&mut self, keyword: Keyword) -> bool { diff --git a/compiler/noirc_frontend/src/parser/parser/arguments.rs b/compiler/noirc_frontend/src/parser/parser/arguments.rs index 808a516b862..6b7dd8559c8 100644 --- a/compiler/noirc_frontend/src/parser/parser/arguments.rs +++ b/compiler/noirc_frontend/src/parser/parser/arguments.rs @@ -1,6 +1,6 @@ use crate::{ast::Expression, token::Token}; -use super::{parse_many::separated_by_comma_until_right_paren, Parser}; +use super::{Parser, parse_many::separated_by_comma_until_right_paren}; pub(crate) struct CallArguments { pub(crate) arguments: Vec, diff --git a/compiler/noirc_frontend/src/parser/parser/attributes.rs b/compiler/noirc_frontend/src/parser/parser/attributes.rs index 0d10744c441..32aa974fcaf 100644 --- a/compiler/noirc_frontend/src/parser/parser/attributes.rs +++ b/compiler/noirc_frontend/src/parser/parser/attributes.rs @@ -2,13 +2,13 @@ use noirc_errors::Location; use crate::ast::{Expression, ExpressionKind, Ident, Literal, Path}; use crate::lexer::errors::LexerErrorKind; -use crate::parser::labels::ParsingRuleLabel; use crate::parser::ParserErrorReason; +use crate::parser::labels::ParsingRuleLabel; use crate::token::{Attribute, FunctionAttribute, MetaAttribute, TestScope, Token}; use crate::token::{CustomAttribute, SecondaryAttribute}; -use super::parse_many::without_separator; use super::Parser; +use super::parse_many::without_separator; impl Parser<'_> { /// InnerAttribute = '#![' SecondaryAttribute ']' @@ -400,7 +400,7 @@ mod tests { use noirc_errors::Span; use crate::{ - parser::{parser::tests::expect_no_errors, Parser}, + parser::{Parser, parser::tests::expect_no_errors}, token::{Attribute, FunctionAttribute, SecondaryAttribute, TestScope}, }; diff --git a/compiler/noirc_frontend/src/parser/parser/doc_comments.rs b/compiler/noirc_frontend/src/parser/parser/doc_comments.rs index 14b79f158bf..0c9329d7027 100644 --- a/compiler/noirc_frontend/src/parser/parser/doc_comments.rs +++ b/compiler/noirc_frontend/src/parser/parser/doc_comments.rs @@ -3,7 +3,7 @@ use crate::{ token::{DocStyle, Token, TokenKind}, }; -use super::{parse_many::without_separator, Parser}; +use super::{Parser, parse_many::without_separator}; impl Parser<'_> { /// InnerDocComments = inner_doc_comment* @@ -47,7 +47,7 @@ impl Parser<'_> { #[cfg(test)] mod tests { - use crate::parser::{parser::tests::expect_no_errors, Parser}; + use crate::parser::{Parser, parser::tests::expect_no_errors}; #[test] fn parses_inner_doc_comments() { diff --git a/compiler/noirc_frontend/src/parser/parser/enums.rs b/compiler/noirc_frontend/src/parser/parser/enums.rs index 857238c4a42..885bfa871ee 100644 --- a/compiler/noirc_frontend/src/parser/parser/enums.rs +++ b/compiler/noirc_frontend/src/parser/parser/enums.rs @@ -7,8 +7,8 @@ use crate::{ }; use super::{ - parse_many::{separated_by_comma_until_right_brace, separated_by_comma_until_right_paren}, Parser, + parse_many::{separated_by_comma_until_right_brace, separated_by_comma_until_right_paren}, }; impl Parser<'_> { @@ -123,8 +123,8 @@ mod tests { ast::{IntegerBitSize, NoirEnumeration, Signedness, UnresolvedGeneric, UnresolvedTypeData}, parse_program_with_dummy_file, parser::{ - parser::tests::{expect_no_errors, get_source_with_error_span}, ItemKind, ParserErrorReason, + parser::tests::{expect_no_errors, get_source_with_error_span}, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/expression.rs b/compiler/noirc_frontend/src/parser/parser/expression.rs index ee2476a71e8..d0f335414da 100644 --- a/compiler/noirc_frontend/src/parser/parser/expression.rs +++ b/compiler/noirc_frontend/src/parser/parser/expression.rs @@ -8,16 +8,16 @@ use crate::{ IndexExpression, Literal, MatchExpression, MemberAccessExpression, MethodCallExpression, Statement, TypePath, UnaryOp, UnresolvedType, UnsafeExpression, }, - parser::{labels::ParsingRuleLabel, parser::parse_many::separated_by_comma, ParserErrorReason}, + parser::{ParserErrorReason, labels::ParsingRuleLabel, parser::parse_many::separated_by_comma}, token::{Keyword, Token, TokenKind}, }; use super::{ + Parser, parse_many::{ separated_by_comma_until_right_brace, separated_by_comma_until_right_paren, without_separator, }, - Parser, }; impl Parser<'_> { @@ -388,20 +388,23 @@ impl Parser<'_> { /// UnsafeExpression = 'unsafe' Block fn parse_unsafe_expr(&mut self) -> Option { let start_location = self.current_token_location; + let comments_before_unsafe = self.current_token_comments.clone(); if !self.eat_keyword(Keyword::Unsafe) { return None; } - if self.current_token_comments.is_empty() { - if let Some(statement_comments) = &mut self.statement_comments { - if !statement_comments.trim().to_lowercase().starts_with("safety:") { - self.push_error(ParserErrorReason::MissingSafetyComment, start_location); - } + let comments: &str = if comments_before_unsafe.is_empty() { + if let Some(statement_comments) = &self.statement_comments { + statement_comments } else { - self.push_error(ParserErrorReason::MissingSafetyComment, start_location); + "" } - } else if !self.current_token_comments.trim().to_lowercase().starts_with("safety:") { + } else { + &comments_before_unsafe + }; + + if !comments.lines().any(|line| line.trim().to_lowercase().starts_with("safety:")) { self.push_error(ParserErrorReason::MissingSafetyComment, start_location); } @@ -887,11 +890,11 @@ mod tests { StatementKind, UnaryOp, UnresolvedTypeData, }, parser::{ + Parser, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error, get_single_error_reason, get_source_with_error_span, }, - Parser, ParserErrorReason, }, signed_field::SignedField, token::Token, @@ -1079,7 +1082,9 @@ mod tests { let src = " // Safety: test unsafe { 1 }"; - let expr = parse_expression_no_errors(src); + let mut parser = Parser::for_str_with_dummy_file(src); + let expr = parser.parse_expression_or_error(); + assert!(parser.errors.is_empty()); let ExpressionKind::Unsafe(unsafe_expression) = expr.kind else { panic!("Expected unsafe expression"); }; diff --git a/compiler/noirc_frontend/src/parser/parser/function.rs b/compiler/noirc_frontend/src/parser/parser/function.rs index 1052f32a2ae..f10b790e63f 100644 --- a/compiler/noirc_frontend/src/parser/parser/function.rs +++ b/compiler/noirc_frontend/src/parser/parser/function.rs @@ -17,7 +17,7 @@ use noirc_errors::{Location, Span}; use super::parse_many::separated_by_comma_until_right_paren; use super::pattern::SelfPattern; -use super::{pattern::PatternOrSelf, Parser}; +use super::{Parser, pattern::PatternOrSelf}; pub(crate) struct FunctionDefinitionWithOptionalBody { pub(crate) name: Ident, @@ -109,10 +109,24 @@ impl Parser<'_> { let visibility = self.parse_visibility(); (FunctionReturnType::Ty(self.parse_type_or_error()), visibility) } else { - ( - FunctionReturnType::Default(self.location_at_previous_token_end()), - Visibility::Private, - ) + // This will return the span between `)` and `{` + // + // fn foo() { } + // ^^^ + let mut location = self.previous_token_location.merge(self.current_token_location); + + // Here we change it to this (if there's space) + // + // fn foo() { } + // ^ + if location.span.end() - location.span.start() >= 3 { + location = Location::new( + Span::from(location.span.start() + 1..location.span.end() - 1), + location.file, + ); + } + + (FunctionReturnType::Default(location), Visibility::Private) }; let where_clause = self.parse_where_clause(); @@ -315,11 +329,11 @@ mod tests { }, parse_program_with_dummy_file, parser::{ + ItemKind, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error, get_single_error_reason, get_source_with_error_span, }, - ItemKind, ParserErrorReason, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/generics.rs b/compiler/noirc_frontend/src/parser/parser/generics.rs index 15f27d35a50..0bac5d5f34b 100644 --- a/compiler/noirc_frontend/src/parser/parser/generics.rs +++ b/compiler/noirc_frontend/src/parser/parser/generics.rs @@ -3,11 +3,11 @@ use crate::{ GenericTypeArg, GenericTypeArgs, IntegerBitSize, Signedness, UnresolvedGeneric, UnresolvedGenerics, UnresolvedType, UnresolvedTypeData, }, - parser::{labels::ParsingRuleLabel, ParserErrorReason}, + parser::{ParserErrorReason, labels::ParsingRuleLabel}, token::{Keyword, Token, TokenKind}, }; -use super::{parse_many::separated_by_comma, Parser}; +use super::{Parser, parse_many::separated_by_comma}; impl Parser<'_> { /// Generics = ( '<' GenericsList? '>' )? @@ -167,10 +167,10 @@ mod tests { use crate::{ ast::{GenericTypeArgs, IntegerBitSize, Signedness, UnresolvedGeneric, UnresolvedTypeData}, parser::{ + Parser, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error_reason, get_source_with_error_span, }, - Parser, ParserErrorReason, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/global.rs b/compiler/noirc_frontend/src/parser/parser/global.rs index 9f4e2a5f932..2edb3eeaa18 100644 --- a/compiler/noirc_frontend/src/parser/parser/global.rs +++ b/compiler/noirc_frontend/src/parser/parser/global.rs @@ -79,11 +79,11 @@ mod tests { }, parse_program_with_dummy_file, parser::{ + ItemKind, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error, get_single_error_reason, get_source_with_error_span, }, - ItemKind, ParserErrorReason, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/impls.rs b/compiler/noirc_frontend/src/parser/parser/impls.rs index 0bc8b8c042d..3fdfbc7d28a 100644 --- a/compiler/noirc_frontend/src/parser/parser/impls.rs +++ b/compiler/noirc_frontend/src/parser/parser/impls.rs @@ -6,11 +6,11 @@ use crate::{ TraitImplItem, TraitImplItemKind, TypeImpl, UnresolvedGeneric, UnresolvedType, UnresolvedTypeData, }, - parser::{labels::ParsingRuleLabel, ParserErrorReason}, + parser::{ParserErrorReason, labels::ParsingRuleLabel}, token::{Keyword, Token}, }; -use super::{parse_many::without_separator, Parser}; +use super::{Parser, parse_many::without_separator}; pub(crate) enum Impl { Impl(TypeImpl), @@ -241,8 +241,8 @@ mod tests { }, parse_program_with_dummy_file, parser::{ - parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, ItemKind, + parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/item.rs b/compiler/noirc_frontend/src/parser/parser/item.rs index 40065895688..121a1e749f2 100644 --- a/compiler/noirc_frontend/src/parser/parser/item.rs +++ b/compiler/noirc_frontend/src/parser/parser/item.rs @@ -1,11 +1,11 @@ use iter_extended::vecmap; use crate::{ - parser::{labels::ParsingRuleLabel, Item, ItemKind, ParserErrorReason}, + parser::{Item, ItemKind, ParserErrorReason, labels::ParsingRuleLabel}, token::{Keyword, Token}, }; -use super::{impls::Impl, parse_many::without_separator, Parser}; +use super::{Parser, impls::Impl, parse_many::without_separator}; impl<'a> Parser<'a> { pub(crate) fn parse_top_level_items(&mut self) -> Vec { diff --git a/compiler/noirc_frontend/src/parser/parser/item_visibility.rs b/compiler/noirc_frontend/src/parser/parser/item_visibility.rs index b91cc397015..91ace6a62ce 100644 --- a/compiler/noirc_frontend/src/parser/parser/item_visibility.rs +++ b/compiler/noirc_frontend/src/parser/parser/item_visibility.rs @@ -39,8 +39,8 @@ mod tests { use crate::{ ast::ItemVisibility, parser::{ - parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, Parser, + parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/lambda.rs b/compiler/noirc_frontend/src/parser/parser/lambda.rs index a40f46ecbb4..25f803c8e1d 100644 --- a/compiler/noirc_frontend/src/parser/parser/lambda.rs +++ b/compiler/noirc_frontend/src/parser/parser/lambda.rs @@ -4,7 +4,7 @@ use crate::{ token::Token, }; -use super::{parse_many::separated_by_comma, Parser}; +use super::{Parser, parse_many::separated_by_comma}; impl Parser<'_> { /// Lambda = '|' LambdaParameters? '|' ( '->' Type )? Expression diff --git a/compiler/noirc_frontend/src/parser/parser/module.rs b/compiler/noirc_frontend/src/parser/parser/module.rs index 9546a4f8cfa..cae0a328d75 100644 --- a/compiler/noirc_frontend/src/parser/parser/module.rs +++ b/compiler/noirc_frontend/src/parser/parser/module.rs @@ -60,7 +60,7 @@ impl Parser<'_> { mod tests { use crate::{ parse_program_with_dummy_file, - parser::{parser::tests::expect_no_errors, ItemKind}, + parser::{ItemKind, parser::tests::expect_no_errors}, }; #[test] diff --git a/compiler/noirc_frontend/src/parser/parser/parse_many.rs b/compiler/noirc_frontend/src/parser/parser/parse_many.rs index 082cee169ca..1c77aac7f18 100644 --- a/compiler/noirc_frontend/src/parser/parser/parse_many.rs +++ b/compiler/noirc_frontend/src/parser/parser/parse_many.rs @@ -42,11 +42,7 @@ impl<'a> Parser<'a> { F: FnMut(&mut Parser<'a>) -> Option, { let f = |x: &mut Parser<'a>| { - if let Some(result) = f(x) { - vec![result] - } else { - vec![] - } + if let Some(result) = f(x) { vec![result] } else { vec![] } }; self.parse_many_to_many_return_trailing_separator_if_any(items, separated_by, f) } diff --git a/compiler/noirc_frontend/src/parser/parser/path.rs b/compiler/noirc_frontend/src/parser/parser/path.rs index e48e37b748a..a58bd9e1bb1 100644 --- a/compiler/noirc_frontend/src/parser/parser/path.rs +++ b/compiler/noirc_frontend/src/parser/parser/path.rs @@ -91,11 +91,7 @@ impl Parser<'_> { start_location, ); - if path.segments.is_empty() && path.kind == PathKind::Plain { - None - } else { - Some(path) - } + if path.segments.is_empty() && path.kind == PathKind::Plain { None } else { Some(path) } } /// Parses a path assuming the path's kind (plain, `crate::`, `super::`, etc.) @@ -218,8 +214,8 @@ mod tests { use crate::{ ast::{Path, PathKind}, parser::{ - parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, Parser, + parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/pattern.rs b/compiler/noirc_frontend/src/parser/parser/pattern.rs index 578b238a1dd..61fb1572c17 100644 --- a/compiler/noirc_frontend/src/parser/parser/pattern.rs +++ b/compiler/noirc_frontend/src/parser/parser/pattern.rs @@ -2,13 +2,13 @@ use noirc_errors::Location; use crate::{ ast::{Ident, Path, Pattern}, - parser::{labels::ParsingRuleLabel, ParserErrorReason}, + parser::{ParserErrorReason, labels::ParsingRuleLabel}, token::{Keyword, Token, TokenKind}, }; use super::{ - parse_many::{separated_by_comma_until_right_brace, separated_by_comma_until_right_paren}, Parser, + parse_many::{separated_by_comma_until_right_brace, separated_by_comma_until_right_paren}, }; pub(crate) enum PatternOrSelf { @@ -254,11 +254,11 @@ mod tests { use crate::{ ast::Pattern, parser::{ + Parser, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error, get_single_error_reason, get_source_with_error_span, }, - Parser, ParserErrorReason, }, token::{Keyword, Token}, }; diff --git a/compiler/noirc_frontend/src/parser/parser/statement.rs b/compiler/noirc_frontend/src/parser/parser/statement.rs index f90173156e7..600ddec43c9 100644 --- a/compiler/noirc_frontend/src/parser/parser/statement.rs +++ b/compiler/noirc_frontend/src/parser/parser/statement.rs @@ -6,7 +6,7 @@ use crate::{ ForLoopStatement, ForRange, Ident, InfixExpression, LValue, LetStatement, Statement, StatementKind, WhileStatement, }, - parser::{labels::ParsingRuleLabel, ParserErrorReason}, + parser::{ParserErrorReason, labels::ParsingRuleLabel}, token::{Attribute, Keyword, Token, TokenKind}, }; @@ -462,11 +462,11 @@ mod tests { use crate::{ ast::{ExpressionKind, ForRange, LValue, Statement, StatementKind, UnresolvedTypeData}, parser::{ + Parser, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error, get_single_error_reason, get_source_with_error_span, }, - Parser, ParserErrorReason, }, }; @@ -521,7 +521,9 @@ mod tests { fn parses_let_statement_with_unsafe() { let src = "// Safety: comment let x = unsafe { 1 };"; - let statement = parse_statement_no_errors(src); + let mut parser = Parser::for_str_with_dummy_file(src); + let statement = parser.parse_statement_or_error(); + assert!(parser.errors.is_empty()); let StatementKind::Let(let_statement) = statement.kind else { panic!("Expected let statement"); }; @@ -540,6 +542,20 @@ mod tests { assert_eq!(let_statement.pattern.to_string(), "x"); } + #[test] + fn parses_let_statement_with_unsafe_after_some_other_comment() { + let src = "// Top comment + // Safety: comment + let x = unsafe { 1 };"; + let mut parser = Parser::for_str_with_dummy_file(src); + let statement = parser.parse_statement_or_error(); + assert!(parser.errors.is_empty()); + let StatementKind::Let(let_statement) = statement.kind else { + panic!("Expected let statement"); + }; + assert_eq!(let_statement.pattern.to_string(), "x"); + } + #[test] fn parses_comptime_block() { let src = "comptime { 1 }"; diff --git a/compiler/noirc_frontend/src/parser/parser/structs.rs b/compiler/noirc_frontend/src/parser/parser/structs.rs index 00bab45e97c..62f49035f72 100644 --- a/compiler/noirc_frontend/src/parser/parser/structs.rs +++ b/compiler/noirc_frontend/src/parser/parser/structs.rs @@ -6,7 +6,7 @@ use crate::{ token::{Attribute, SecondaryAttribute, Token}, }; -use super::{parse_many::separated_by_comma_until_right_brace, Parser}; +use super::{Parser, parse_many::separated_by_comma_until_right_brace}; impl Parser<'_> { /// Struct = 'struct' identifier Generics '{' StructField* '}' @@ -132,11 +132,11 @@ mod tests { ast::{IntegerBitSize, NoirStruct, Signedness, UnresolvedGeneric, UnresolvedTypeData}, parse_program_with_dummy_file, parser::{ + ItemKind, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error, get_single_error_reason, get_source_with_error_span, }, - ItemKind, ParserErrorReason, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index 80e336f4c81..c37163ebc36 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -8,12 +8,12 @@ use crate::ast::{ }; use crate::{ ast::{Ident, UnresolvedTypeData}, - parser::{labels::ParsingRuleLabel, NoirTraitImpl, ParserErrorReason}, + parser::{NoirTraitImpl, ParserErrorReason, labels::ParsingRuleLabel}, token::{Attribute, Keyword, SecondaryAttribute, Token}, }; -use super::parse_many::without_separator; use super::Parser; +use super::parse_many::without_separator; impl Parser<'_> { /// Trait = 'trait' identifier Generics ( ':' TraitBounds )? WhereClause TraitBody @@ -291,11 +291,11 @@ mod tests { ast::{NoirTrait, NoirTraitImpl, TraitItem, UnresolvedTypeData}, parse_program_with_dummy_file, parser::{ + ItemKind, parser::{ - tests::{expect_no_errors, get_single_error, get_source_with_error_span}, ParserErrorReason, + tests::{expect_no_errors, get_single_error, get_source_with_error_span}, }, - ItemKind, }, }; diff --git a/compiler/noirc_frontend/src/parser/parser/type_alias.rs b/compiler/noirc_frontend/src/parser/parser/type_alias.rs index 50e67ec6d53..464e3e897c5 100644 --- a/compiler/noirc_frontend/src/parser/parser/type_alias.rs +++ b/compiler/noirc_frontend/src/parser/parser/type_alias.rs @@ -57,7 +57,7 @@ mod tests { use crate::{ ast::{NoirTypeAlias, UnresolvedTypeData}, parse_program_with_dummy_file, - parser::{parser::tests::expect_no_errors, ItemKind}, + parser::{ItemKind, parser::tests::expect_no_errors}, }; fn parse_type_alias_no_errors(src: &str) -> NoirTypeAlias { diff --git a/compiler/noirc_frontend/src/parser/parser/type_expression.rs b/compiler/noirc_frontend/src/parser/parser/type_expression.rs index 1b4eaabaf35..f6d6dbd8a25 100644 --- a/compiler/noirc_frontend/src/parser/parser/type_expression.rs +++ b/compiler/noirc_frontend/src/parser/parser/type_expression.rs @@ -1,14 +1,14 @@ use crate::{ + BinaryTypeOperator, ast::{GenericTypeArgs, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression}, - parser::{labels::ParsingRuleLabel, ParserError}, + parser::{ParserError, labels::ParsingRuleLabel}, token::Token, - BinaryTypeOperator, }; use acvm::acir::{AcirField, FieldElement}; use noirc_errors::Location; -use super::{parse_many::separated_by_comma_until_right_paren, Parser}; +use super::{Parser, parse_many::separated_by_comma_until_right_paren}; impl Parser<'_> { /// TypeExpression= AddOrSubtractTypeExpression @@ -394,15 +394,15 @@ mod tests { use core::panic; use crate::{ + BinaryTypeOperator, ast::{UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression}, parser::{ + Parser, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error_reason, get_source_with_error_span, }, - Parser, ParserErrorReason, }, token::Token, - BinaryTypeOperator, }; fn parse_type_expression_no_errors(src: &str) -> UnresolvedTypeExpression { diff --git a/compiler/noirc_frontend/src/parser/parser/types.rs b/compiler/noirc_frontend/src/parser/parser/types.rs index b8551fd5352..bcbf57d863d 100644 --- a/compiler/noirc_frontend/src/parser/parser/types.rs +++ b/compiler/noirc_frontend/src/parser/parser/types.rs @@ -1,13 +1,13 @@ use acvm::{AcirField, FieldElement}; use crate::{ + QuotedType, ast::{UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression}, - parser::{labels::ParsingRuleLabel, ParserErrorReason}, + parser::{ParserErrorReason, labels::ParsingRuleLabel}, token::{Keyword, Token, TokenKind}, - QuotedType, }; -use super::{parse_many::separated_by_comma_until_right_paren, Parser}; +use super::{Parser, parse_many::separated_by_comma_until_right_paren}; impl Parser<'_> { pub(crate) fn parse_type_or_error(&mut self) -> UnresolvedType { @@ -320,11 +320,7 @@ impl Parser<'_> { fn parse_parameter(&mut self) -> Option { let typ = self.parse_type_or_error(); - if let UnresolvedTypeData::Error = typ.typ { - None - } else { - Some(typ) - } + if let UnresolvedTypeData::Error = typ.typ { None } else { Some(typ) } } fn parse_trait_as_type(&mut self) -> Option { @@ -462,12 +458,12 @@ mod tests { use strum::IntoEnumIterator; use crate::{ + QuotedType, ast::{IntegerBitSize, Signedness, UnresolvedType, UnresolvedTypeData}, parser::{ - parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, Parser, ParserErrorReason, + parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, }, - QuotedType, }; fn parse_type_no_errors(src: &str) -> UnresolvedType { diff --git a/compiler/noirc_frontend/src/parser/parser/use_tree.rs b/compiler/noirc_frontend/src/parser/parser/use_tree.rs index 393af80dd29..ebe05863211 100644 --- a/compiler/noirc_frontend/src/parser/parser/use_tree.rs +++ b/compiler/noirc_frontend/src/parser/parser/use_tree.rs @@ -6,7 +6,7 @@ use crate::{ token::{Keyword, Token}, }; -use super::{parse_many::separated_by_comma_until_right_brace, Parser}; +use super::{Parser, parse_many::separated_by_comma_until_right_brace}; impl Parser<'_> { /// Use = 'use' PathKind PathNoTurbofish UseTree @@ -147,7 +147,7 @@ mod tests { use crate::{ ast::{ItemVisibility, PathKind, UseTree, UseTreeKind}, parse_program_with_dummy_file, - parser::{parser::tests::expect_no_errors, ItemKind}, + parser::{ItemKind, parser::tests::expect_no_errors}, }; fn parse_use_tree_no_errors(src: &str) -> (UseTree, ItemVisibility) { diff --git a/compiler/noirc_frontend/src/parser/parser/where_clause.rs b/compiler/noirc_frontend/src/parser/parser/where_clause.rs index 97cf8854cc1..08adea0a20a 100644 --- a/compiler/noirc_frontend/src/parser/parser/where_clause.rs +++ b/compiler/noirc_frontend/src/parser/parser/where_clause.rs @@ -5,8 +5,8 @@ use crate::{ }; use super::{ - parse_many::{separated_by, separated_by_comma}, Parser, + parse_many::{separated_by, separated_by_comma}, }; impl Parser<'_> { @@ -89,10 +89,10 @@ mod tests { use crate::{ ast::UnresolvedTraitConstraint, parser::{ + Parser, ParserErrorReason, parser::tests::{ expect_no_errors, get_single_error_reason, get_source_with_error_span, }, - Parser, ParserErrorReason, }, token::Token, }; diff --git a/compiler/noirc_frontend/src/signed_field.rs b/compiler/noirc_frontend/src/signed_field.rs index 06a0689ceaf..dcddd52daa8 100644 --- a/compiler/noirc_frontend/src/signed_field.rs +++ b/compiler/noirc_frontend/src/signed_field.rs @@ -88,11 +88,7 @@ impl std::ops::Neg for SignedField { impl Ord for SignedField { fn cmp(&self, other: &Self) -> std::cmp::Ordering { if self.is_negative != other.is_negative { - if self.is_negative { - std::cmp::Ordering::Less - } else { - std::cmp::Ordering::Greater - } + if self.is_negative { std::cmp::Ordering::Less } else { std::cmp::Ordering::Greater } } else if self.is_negative { // Negative comparisons should be reversed so that -2 < -1 other.field.cmp(&self.field) @@ -116,11 +112,7 @@ impl From for SignedField { impl From for FieldElement { fn from(value: SignedField) -> Self { - if value.is_negative { - -value.field - } else { - value.field - } + if value.is_negative { -value.field } else { value.field } } } diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 988991d3efd..e53aa392fa9 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -24,9 +24,9 @@ use fm::FileId; use iter_extended::vecmap; use noirc_errors::{CustomDiagnostic, Location, Span}; +use crate::hir::Context; use crate::hir::def_collector::dc_crate::CompilationError; use crate::hir::def_map::ModuleData; -use crate::hir::Context; use crate::node_interner::{NodeInterner, StmtId}; use crate::hir::def_collector::dc_crate::DefCollector; @@ -38,7 +38,7 @@ use crate::monomorphization::errors::MonomorphizationError; use crate::monomorphization::monomorphize; use crate::parser::{ItemKind, ParserErrorReason}; use crate::token::SecondaryAttribute; -use crate::{parse_program, ParsedModule}; +use crate::{ParsedModule, parse_program}; use fm::FileManager; use noirc_arena::Arena; @@ -232,9 +232,13 @@ fn check_errors_with_options(src: &str, allow_parser_errors: bool, options: Fron let Some(expected_message) = primary_spans_with_errors.remove(&span) else { if let Some(message) = secondary_spans_with_errors.get(&span) { - panic!("Error at {span:?} with message {message:?} is annotated as secondary but should be primary"); + panic!( + "Error at {span:?} with message {message:?} is annotated as secondary but should be primary" + ); } else { - panic!("Couldn't find primary error at {span:?} with message {message:?}.\nAll errors: {errors:?}"); + panic!( + "Couldn't find primary error at {span:?} with message {message:?}.\nAll errors: {errors:?}" + ); } }; @@ -249,9 +253,13 @@ fn check_errors_with_options(src: &str, allow_parser_errors: bool, options: Fron let span = secondary.location.span; let Some(expected_message) = secondary_spans_with_errors.remove(&span) else { if let Some(message) = primary_spans_with_errors.get(&span) { - panic!("Error at {span:?} with message {message:?} is annotated as primary but should be secondary"); + panic!( + "Error at {span:?} with message {message:?} is annotated as primary but should be secondary" + ); } else { - panic!("Couldn't find secondary error at {span:?} with message {message:?}.\nAll errors: {errors:?}"); + panic!( + "Couldn't find secondary error at {span:?} with message {message:?}.\nAll errors: {errors:?}" + ); }; }; @@ -354,12 +362,12 @@ fn check_trait_implementation_duplicate_method() { impl Default for Foo { // Duplicate trait methods should not compile fn default(x: Field, y: Field) -> Field { - ^^^^^^^ Duplicate definitions of trait associated function with name default found ~~~~~~~ First trait associated function found here y + 2 * x } // Duplicate trait methods should not compile fn default(x: Field, y: Field) -> Field { + ^^^^^^^ Duplicate definitions of trait associated function with name default found ~~~~~~~ Second trait associated function found here x + 2 * y } @@ -373,7 +381,6 @@ fn check_trait_implementation_duplicate_method() { #[test] fn check_trait_wrong_method_return_type() { - // TODO: improve the error location let src = " trait Default { fn default() -> Self; @@ -384,7 +391,7 @@ fn check_trait_wrong_method_return_type() { impl Default for Foo { fn default() -> Field { - ^^^^^^^ Expected type Foo, found type Field + ^^^^^ Expected type Foo, found type Field 0 } } @@ -398,7 +405,6 @@ fn check_trait_wrong_method_return_type() { #[test] fn check_trait_wrong_method_return_type2() { - // TODO: improve the error location let src = " trait Default { fn default(x: Field, y: Field) -> Self; @@ -411,7 +417,7 @@ fn check_trait_wrong_method_return_type2() { impl Default for Foo { fn default(x: Field, _y: Field) -> Field { - ^^^^^^^ Expected type Foo, found type Field + ^^^^^ Expected type Foo, found type Field x } } @@ -422,6 +428,31 @@ fn check_trait_wrong_method_return_type2() { check_errors(src); } +#[test] +fn check_trait_wrong_method_return_type3() { + let src = " + trait Default { + fn default(x: Field, y: Field) -> Self; + } + + struct Foo { + bar: Field, + array: [Field; 2], + } + + impl Default for Foo { + fn default(_x: Field, _y: Field) { + ^ Expected type Foo, found type () + } + } + + fn main() { + let _ = Foo { bar: 1, array: [2, 3] }; // silence Foo never constructed warning + } + "; + check_errors(src); +} + #[test] fn check_trait_missing_implementation() { let src = " @@ -498,7 +529,6 @@ fn check_trait_wrong_method_name() { #[test] fn check_trait_wrong_parameter() { - // TODO: improve the error location let src = " trait Default { fn default(x: Field) -> Self; @@ -510,7 +540,7 @@ fn check_trait_wrong_parameter() { impl Default for Foo { fn default(x: u32) -> Self { - ^ Parameter #1 of method `default` must be of type Field, not u32 + ^^^ Parameter #1 of method `default` must be of type Field, not u32 Foo {bar: x} } } @@ -535,7 +565,7 @@ fn check_trait_wrong_parameter2() { impl Default for Foo { fn default(x: Field, y: Foo) -> Self { - ^ Parameter #2 of method `default` must be of type Field, not Foo + ^^^ Parameter #2 of method `default` must be of type Field, not Foo Self { bar: x, array: [x, y.bar] } } } @@ -636,7 +666,6 @@ fn check_impl_struct_not_trait() { fn check_trait_duplicate_declaration() { let src = " trait Default { - ^^^^^^^ Duplicate definitions of trait definition with name Default found ~~~~~~~ First trait definition found here fn default(x: Field, y: Field) -> Self; } @@ -653,6 +682,7 @@ fn check_trait_duplicate_declaration() { } trait Default { + ^^^^^^^ Duplicate definitions of trait definition with name Default found ~~~~~~~ Second trait definition found here fn default(x: Field) -> Self; } @@ -1491,15 +1521,15 @@ fn numeric_generic_binary_operation_type_mismatch() { #[test] fn bool_generic_as_loop_bound() { - // TODO: improve the error location of the last error (should be just on N) let src = r#" pub fn read() { ^ N has a type of bool. The only supported numeric generic types are `u1`, `u8`, `u16`, and `u32`. ~ Unsupported numeric generic type let mut fields = [0; N]; - ^ Expected kind numeric u32, found kind numeric bool + ^ The numeric generic is not of type `u32` + ~ expected `u32`, found `bool` for i in 0..N { - ^^^^ Expected type Field, found type bool + ^ Expected type Field, found type bool fields[i] = i + 1; } assert(fields[0] == 1); @@ -1508,6 +1538,19 @@ fn bool_generic_as_loop_bound() { check_errors(src); } +#[test] +fn wrong_type_in_for_range() { + let src = r#" + pub fn foo() { + for _ in true..false { + ^^^^ The type bool cannot be used in a for loop + + } + } + "#; + check_errors(src); +} + #[test] fn numeric_generic_in_function_signature() { let src = r#" @@ -1518,13 +1561,12 @@ fn numeric_generic_in_function_signature() { #[test] fn numeric_generic_as_struct_field_type_fails() { - // TODO: improve error message, in Rust it says "expected type, found const parameter `N`" - // which might be more understandable let src = r#" pub struct Foo { a: Field, b: N, - ^ Expected kind normal, found kind numeric u32 + ^ Expected type, found numeric generic + ~ not a type } "#; check_errors(src); @@ -1537,7 +1579,8 @@ fn normal_generic_as_array_length() { pub struct Foo { a: Field, b: [Field; N], - ^^^^^^^^^^ Expected kind numeric u32, found kind normal + ^^^^^^^^^^ Type provided when a numeric generic was expected + ~~~~~~~~~~ the numeric generic is not of type `u32` } "#; check_errors(src); @@ -1545,13 +1588,17 @@ fn normal_generic_as_array_length() { #[test] fn numeric_generic_as_param_type() { - // TODO: improve the error message, see what Rust does let src = r#" pub fn foo(x: I) -> I { - ^ Expected kind normal, found kind numeric u32 - ^ Expected kind normal, found kind numeric u32 + ^ Expected type, found numeric generic + ~ not a type + ^ Expected type, found numeric generic + ~ not a type + + let _q: I = 5; - ^ Expected kind normal, found kind numeric u32 + ^ Expected type, found numeric generic + ~ not a type x } "#; @@ -1560,23 +1607,23 @@ fn numeric_generic_as_param_type() { #[test] fn numeric_generic_as_unused_param_type() { - // TODO: improve the error message let src = r#" pub fn foo(_x: I) { } - ^ Expected kind normal, found kind numeric u32 + ^ Expected type, found numeric generic + ~ not a type "#; check_errors(src); } #[test] fn numeric_generic_as_unused_trait_fn_param_type() { - // TODO: improve the error message let src = r#" trait Foo { ^^^ unused trait Foo ~~~ unused trait fn foo(_x: I) { } - ^ Expected kind normal, found kind numeric u32 + ^ Expected type, found numeric generic + ~ not a type } "#; check_errors(src); @@ -1584,7 +1631,6 @@ fn numeric_generic_as_unused_trait_fn_param_type() { #[test] fn numeric_generic_as_return_type() { - // TODO: improve the error message let src = r#" // std::mem::zeroed() without stdlib trait Zeroed { @@ -1592,7 +1638,8 @@ fn numeric_generic_as_return_type() { } fn foo(x: T) -> I where T: Zeroed { - ^ Expected kind normal, found kind numeric Field + ^ Expected type, found numeric generic + ~ not a type ^^^ unused function foo ~~~ unused function x.zeroed() @@ -1605,7 +1652,6 @@ fn numeric_generic_as_return_type() { #[test] fn numeric_generic_used_in_nested_type_fails() { - // TODO: improve the error message let src = r#" pub struct Foo { a: Field, @@ -1613,7 +1659,8 @@ fn numeric_generic_used_in_nested_type_fails() { } pub struct Bar { inner: N - ^ Expected kind normal, found kind numeric u32 + ^ Expected type, found numeric generic + ~ not a type } "#; check_errors(src); @@ -1621,12 +1668,12 @@ fn numeric_generic_used_in_nested_type_fails() { #[test] fn normal_generic_used_in_nested_array_length_fail() { - // TODO: improve the error message let src = r#" pub struct Foo { a: Field, b: Bar, - ^ Expected kind numeric u32, found kind normal + ^ Type provided when a numeric generic was expected + ~ the numeric generic is not of type `u32` } pub struct Bar { inner: [Field; N] @@ -1747,7 +1794,7 @@ fn numeric_generic_used_in_turbofish() { // allow u16 to be used as an array size #[test] fn numeric_generic_u16_array_size() { - // TODO: improve the error location (and maybe the message) + // TODO: improve the error location let src = r#" fn len(_arr: [Field; N]) -> u32 { N @@ -1755,8 +1802,10 @@ fn numeric_generic_u16_array_size() { pub fn foo() -> u32 { let fields: [Field; N] = [0; N]; - ^^^^^^^^^^ Expected kind numeric u32, found kind numeric u16 - ^ Expected kind numeric u32, found kind numeric u16 + ^ The numeric generic is not of type `u32` + ~ expected `u32`, found `u16` + ^^^^^^^^^^ The numeric generic is not of type `u32` + ~~~~~~~~~~ expected `u32`, found `u16` len(fields) } "#; @@ -1856,7 +1905,8 @@ fn normal_generic_used_when_numeric_expected_in_where_clause() { } pub fn read() -> T where T: Deserialize { - ^ Expected kind numeric u32, found kind normal + ^ Type provided when a numeric generic was expected + ~ the numeric generic is not of type `u32` T::deserialize([0, 1]) } "#; @@ -1869,10 +1919,13 @@ fn normal_generic_used_when_numeric_expected_in_where_clause() { } pub fn read() -> T where T: Deserialize { - ^ Expected kind numeric u32, found kind normal + ^ Type provided when a numeric generic was expected + ~ the numeric generic is not of type `u32` let mut fields: [Field; N] = [0; N]; - ^ Expected kind numeric u32, found kind normal - ^^^^^^^^^^ Expected kind numeric u32, found kind normal + ^ Type provided when a numeric generic was expected + ~ the numeric generic is not of type `u32` + ^^^^^^^^^^ Type provided when a numeric generic was expected + ~~~~~~~~~~ the numeric generic is not of type `u32` for i in 0..N { ^ cannot find `N` in this scope ~ not found in this scope @@ -1895,7 +1948,8 @@ fn numeric_generics_type_kind_mismatch() { fn bar() -> u16 { foo::() - ^ Expected kind numeric u32, found kind numeric u16 + ^ The numeric generic is not of type `u32` + ~ expected `u32`, found `u16` } global M: u16 = 3; @@ -2413,13 +2467,12 @@ fn bit_not_on_untyped_integer() { #[test] fn duplicate_struct_field() { - // TODO: the primary error location should be on the second field let src = r#" pub struct Foo { x: i32, - ^ Duplicate definitions of struct field with name x found ~ First struct field found here x: i32, + ^ Duplicate definitions of struct field with name x found ~ Second struct field found here } @@ -2538,7 +2591,7 @@ fn uses_self_type_in_trait_where_clause() { } pub trait Foo where Self: Trait { - ~~~~~ required by this bound in `Foo + ~~~~~ required by this bound in `Foo` fn foo(self) -> bool { self.trait_func() ^^^^^^^^^^^^^^^^^ No method named 'trait_func' found for type 'Bar' @@ -2549,7 +2602,7 @@ fn uses_self_type_in_trait_where_clause() { impl Foo for Bar { ^^^ The trait bound `_: Trait` is not satisfied - ~~~ The trait `Trait` is not implemented for `_ + ~~~ The trait `Trait` is not implemented for `_` } @@ -2727,25 +2780,27 @@ fn as_trait_path_syntax_no_impl() { #[test] fn do_not_infer_globals_to_u32_from_type_use() { - // TODO: improve the error location (maybe it should be on the global name) let src = r#" global ARRAY_LEN = 3; - ^ Globals must have a specified type + ^^^^^^^^^ Globals must have a specified type ~ Inferred type is `Field` global STR_LEN: _ = 2; - ^ Globals must have a specified type + ^^^^^^^ Globals must have a specified type ~ Inferred type is `Field` global FMT_STR_LEN = 2; - ^ Globals must have a specified type + ^^^^^^^^^^^ Globals must have a specified type ~ Inferred type is `Field` fn main() { let _a: [u32; ARRAY_LEN] = [1, 2, 3]; - ^^^^^^^^^^^^^^^^ Expected kind numeric u32, found kind numeric Field + ^^^^^^^^^^^^^^^^ The numeric generic is not of type `u32` + ~~~~~~~~~~~~~~~~ expected `u32`, found `Field` let _b: str = "hi"; - ^^^^^^^^^^^^ Expected kind numeric u32, found kind numeric Field + ^^^^^^^^^^^^ The numeric generic is not of type `u32` + ~~~~~~~~~~~~ expected `u32`, found `Field` let _c: fmtstr = f"hi"; - ^^^^^^^^^^^^^^^^^^^^^^ Expected kind numeric u32, found kind numeric Field + ^^^^^^^^^^^^^^^^^^^^^^ The numeric generic is not of type `u32` + ~~~~~~~~~~~~~~~~~~~~~~ expected `u32`, found `Field` } "#; check_errors(src); @@ -2755,25 +2810,25 @@ fn do_not_infer_globals_to_u32_from_type_use() { fn do_not_infer_partial_global_types() { let src = r#" pub global ARRAY: [Field; _] = [0; 3]; - ^^^^^^ Globals must have a specified type + ^^^^^ Globals must have a specified type ~~~~~~ Inferred type is `[Field; 3]` pub global NESTED_ARRAY: [[Field; _]; 3] = [[]; 3]; - ^^^^^^^ Globals must have a specified type + ^^^^^^^^^^^^ Globals must have a specified type ~~~~~~~ Inferred type is `[[Field; 0]; 3]` pub global STR: str<_> = "hi"; - ^^^^ Globals must have a specified type + ^^^ Globals must have a specified type ~~~~ Inferred type is `str<2>` pub global NESTED_STR: [str<_>] = &["hi"]; - ^^^^^^^ Globals must have a specified type + ^^^^^^^^^^ Globals must have a specified type ~~~~~~~ Inferred type is `[str<2>]` pub global FORMATTED_VALUE: str<5> = "there"; pub global FMT_STR: fmtstr<_, _> = f"hi {FORMATTED_VALUE}"; - ^^^^^^^^^^^^^^^^^^^^^^^ Globals must have a specified type + ^^^^^^^ Globals must have a specified type ~~~~~~~~~~~~~~~~~~~~~~~ Inferred type is `fmtstr<20, (str<5>)>` pub global TUPLE_WITH_MULTIPLE: ([str<_>], [[Field; _]; 3]) = + ^^^^^^^^^^^^^^^^^^^ Globals must have a specified type (&["hi"], [[]; 3]); - ^^^^^^^^^^^^^^^^^^ Globals must have a specified type ~~~~~~~~~~~~~~~~~~ Inferred type is `([str<2>], [[Field; 0]; 3])` fn main() { } @@ -2831,7 +2886,8 @@ fn non_u32_as_array_length() { fn main() { let _a: [u32; ARRAY_LEN] = [1, 2, 3]; - ^^^^^^^^^^^^^^^^ Expected kind numeric u32, found kind numeric u8 + ^^^^^^^^^^^^^^^^ The numeric generic is not of type `u32` + ~~~~~~~~~~~~~~~~ expected `u32`, found `u8` } "#; check_errors(src); @@ -3842,15 +3898,14 @@ fn errors_if_while_body_type_is_not_unit() { #[test] fn check_impl_duplicate_method_without_self() { - // TODO: the primary error location should be n the second `foo` let src = " pub struct Foo {} impl Foo { fn foo() {} - ^^^ duplicate definitions of foo found ~~~ first definition found here fn foo() {} + ^^^ duplicate definitions of foo found ~~~ second definition found here } diff --git a/compiler/noirc_frontend/src/tests/enums.rs b/compiler/noirc_frontend/src/tests/enums.rs index 78f0442bc9f..6163b34003e 100644 --- a/compiler/noirc_frontend/src/tests/enums.rs +++ b/compiler/noirc_frontend/src/tests/enums.rs @@ -8,13 +8,12 @@ use super::{check_errors, check_errors_using_features}; #[test] fn error_with_duplicate_enum_variant() { - // TODO: the primary error should be on the second `Bar` let src = r#" pub enum Foo { Bar(i32), - ^^^ Duplicate definitions of enum variant with name Bar found ~~~ First enum variant found here Bar(u8), + ^^^ Duplicate definitions of enum variant with name Bar found ~~~ Second enum variant found here } diff --git a/compiler/noirc_frontend/src/tests/traits.rs b/compiler/noirc_frontend/src/tests/traits.rs index 5ba63bc6a29..d2f9d9a9672 100644 --- a/compiler/noirc_frontend/src/tests/traits.rs +++ b/compiler/noirc_frontend/src/tests/traits.rs @@ -102,11 +102,10 @@ fn trait_inheritance_with_generics_4() { #[test] fn trait_inheritance_dependency_cycle() { - // TODO: maybe the error location should be just on Foo let src = r#" trait Foo: Bar {} - ^^^^^^^^^^^^^^^^^ Dependency cycle found - ~~~~~~~~~~~~~~~~~ 'Foo' recursively depends on itself: Foo -> Bar -> Foo + ^^^ Dependency cycle found + ~~~ 'Foo' recursively depends on itself: Foo -> Bar -> Foo trait Bar: Foo {} fn main() {} "#; @@ -115,18 +114,17 @@ fn trait_inheritance_dependency_cycle() { #[test] fn trait_inheritance_missing_parent_implementation() { - // TODO: the secondary errors are missing a closing backtick let src = r#" pub trait Foo {} pub trait Bar: Foo {} - ~~~ required by this bound in `Bar + ~~~ required by this bound in `Bar` pub struct Struct {} impl Bar for Struct {} ^^^^^^ The trait bound `Struct: Foo` is not satisfied - ~~~~~~ The trait `Foo` is not implemented for `Struct + ~~~~~~ The trait `Foo` is not implemented for `Struct` fn main() { let _ = Struct {}; // silence Struct never constructed warning @@ -214,7 +212,7 @@ fn errors_if_impl_trait_constraint_is_not_satisfied() { pub trait Foo where T: Greeter, - ~~~~~~~ required by this bound in `Foo + ~~~~~~~ required by this bound in `Foo` { fn greet(object: U) where @@ -230,7 +228,7 @@ fn errors_if_impl_trait_constraint_is_not_satisfied() { impl Foo for Bar {} ^^^ The trait bound `SomeGreeter: Greeter` is not satisfied - ~~~ The trait `Greeter` is not implemented for `SomeGreeter + ~~~ The trait `Greeter` is not implemented for `SomeGreeter` fn main() {} "#; @@ -1214,3 +1212,36 @@ fn calls_trait_method_using_struct_name_when_multiple_impls_exist_and_errors_tur "#; check_errors(src); } + +#[test] +fn as_trait_path_in_expression() { + let src = r#" + fn main() { + cursed::(); + } + + fn cursed() + where T: Foo + Foo2 + { + ::bar(1); + ::bar(()); + + // Use each function with different generic arguments + ::bar(()); + } + + trait Foo { fn bar(x: U); } + trait Foo2 { fn bar(x: U); } + + pub struct S {} + + impl Foo for S { + fn bar(_x: Z) {} + } + + impl Foo2 for S { + fn bar(_x: Z) {} + } + "#; + assert_no_errors(src); +} diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index 998c4f719e2..8c0359bbced 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -5,7 +5,7 @@ use js_sys::{JsString, Object}; use nargo::parse_all; use noirc_artifacts::{contract::ContractArtifact, program::ProgramArtifact}; use noirc_driver::{ - add_dep, file_manager_with_stdlib, prepare_crate, prepare_dependency, CompileOptions, + CompileOptions, add_dep, file_manager_with_stdlib, prepare_crate, prepare_dependency, }; use noirc_evaluator::errors::SsaReport; use noirc_frontend::{ @@ -130,7 +130,7 @@ pub(crate) struct DependencyGraph { pub(crate) root_dependencies: Vec, pub(crate) library_dependencies: BTreeMap>, } -/// This is map contains the paths of all of the files in the entry-point crate and +/// This map contains the paths of all of the files in the entry-point crate and /// the transitive dependencies of the entry-point crate. /// /// This is for all intents and purposes the file system that the compiler will use to resolve/compile @@ -176,7 +176,7 @@ pub fn compile_program( let compiled_program = noirc_driver::compile_main(&mut context, crate_id, &compile_options, None) .map_err(|errs| { - CompileError::with_file_diagnostics( + CompileError::with_custom_diagnostics( "Failed to compile program", errs, &context.file_manager, @@ -186,7 +186,7 @@ pub fn compile_program( let optimized_program = nargo::ops::transform_program(compiled_program, expression_width); nargo::ops::check_program(&optimized_program).map_err(|errs| { - CompileError::with_file_diagnostics( + CompileError::with_custom_diagnostics( "Compiled program is not solvable", errs, &context.file_manager, @@ -212,8 +212,8 @@ pub fn compile_contract( let compiled_contract = noirc_driver::compile_contract(&mut context, crate_id, &compile_options) - .map_err(|errs: Vec| { - CompileError::with_file_diagnostics( + .map_err(|errs: Vec| { + CompileError::with_custom_diagnostics( "Failed to compile contract", errs, &context.file_manager, @@ -316,7 +316,7 @@ mod test { use crate::compile::PathToFileSourceMap; - use super::{file_manager_with_source_map, process_dependency_graph, DependencyGraph}; + use super::{DependencyGraph, file_manager_with_source_map, process_dependency_graph}; use std::{collections::BTreeMap, path::Path}; fn setup_test_context(source_map: PathToFileSourceMap) -> Context<'static, 'static> { diff --git a/compiler/wasm/src/compile_new.rs b/compiler/wasm/src/compile_new.rs index ac2f79147b3..37065c8f825 100644 --- a/compiler/wasm/src/compile_new.rs +++ b/compiler/wasm/src/compile_new.rs @@ -1,12 +1,12 @@ use crate::compile::{ - file_manager_with_source_map, JsCompileContractResult, JsCompileProgramResult, - PathToFileSourceMap, + JsCompileContractResult, JsCompileProgramResult, PathToFileSourceMap, + file_manager_with_source_map, }; use crate::errors::{CompileError, JsCompileError}; use acvm::acir::circuit::ExpressionWidth; use nargo::parse_all; use noirc_driver::{ - add_dep, compile_contract, compile_main, prepare_crate, prepare_dependency, CompileOptions, + CompileOptions, add_dep, compile_contract, compile_main, prepare_crate, prepare_dependency, }; use noirc_frontend::{ graph::{CrateId, CrateName}, @@ -109,7 +109,7 @@ impl CompilerContext { let compiled_program = compile_main(&mut self.context, root_crate_id, &compile_options, None) .map_err(|errs| { - CompileError::with_file_diagnostics( + CompileError::with_custom_diagnostics( "Failed to compile program", errs, &self.context.file_manager, @@ -119,7 +119,7 @@ impl CompilerContext { let optimized_program = nargo::ops::transform_program(compiled_program, expression_width); nargo::ops::check_program(&optimized_program).map_err(|errs| { - CompileError::with_file_diagnostics( + CompileError::with_custom_diagnostics( "Compiled program is not solvable", errs, &self.context.file_manager, @@ -148,7 +148,7 @@ impl CompilerContext { let compiled_contract = compile_contract(&mut self.context, root_crate_id, &compile_options) .map_err(|errs| { - CompileError::with_file_diagnostics( + CompileError::with_custom_diagnostics( "Failed to compile contract", errs, &self.context.file_manager, @@ -280,7 +280,7 @@ mod test { use noirc_driver::prepare_crate; use noirc_frontend::hir::Context; - use crate::compile::{file_manager_with_source_map, PathToFileSourceMap}; + use crate::compile::{PathToFileSourceMap, file_manager_with_source_map}; use std::path::Path; diff --git a/compiler/wasm/src/errors.rs b/compiler/wasm/src/errors.rs index c2e51162d3f..47927df1056 100644 --- a/compiler/wasm/src/errors.rs +++ b/compiler/wasm/src/errors.rs @@ -4,7 +4,7 @@ use serde::Serialize; use wasm_bindgen::prelude::*; use fm::FileManager; -use noirc_errors::FileDiagnostic; +use noirc_errors::CustomDiagnostic; #[wasm_bindgen(typescript_custom_section)] const DIAGNOSTICS: &'static str = r#" @@ -87,8 +87,7 @@ pub struct Diagnostic { } impl Diagnostic { - fn new(file_diagnostic: &FileDiagnostic, file: String) -> Diagnostic { - let diagnostic = &file_diagnostic.diagnostic; + fn new(diagnostic: &CustomDiagnostic, file: String) -> Diagnostic { let message = diagnostic.message.clone(); let secondaries = diagnostic @@ -116,16 +115,16 @@ impl CompileError { CompileError { message: message.to_string(), diagnostics: vec![] } } - pub fn with_file_diagnostics( + pub fn with_custom_diagnostics( message: &str, - file_diagnostics: Vec, + custom_diagnostics: Vec, file_manager: &FileManager, ) -> CompileError { - let diagnostics: Vec<_> = file_diagnostics + let diagnostics: Vec<_> = custom_diagnostics .iter() .map(|err| { let file_path = file_manager - .path(err.file_id) + .path(err.file) .expect("File must exist to have caused diagnostics"); Diagnostic::new(err, file_path.to_str().unwrap().to_string()) }) diff --git a/compiler/wasm/src/lib.rs b/compiler/wasm/src/lib.rs index 6753faf2009..d24b6f4ed01 100644 --- a/compiler/wasm/src/lib.rs +++ b/compiler/wasm/src/lib.rs @@ -10,8 +10,8 @@ use gloo_utils::format::JsValueSerdeExt; use noirc_driver::{GIT_COMMIT, GIT_DIRTY, NOIRC_VERSION}; use serde::{Deserialize, Serialize}; -use tracing_subscriber::prelude::*; use tracing_subscriber::EnvFilter; +use tracing_subscriber::prelude::*; use tracing_web::MakeWebConsoleWriter; mod compile; @@ -21,8 +21,8 @@ mod errors; pub use compile::{compile_contract, compile_program}; // Expose the new Context-Centric API -pub use compile_new::{compile_contract_, compile_program_, CompilerContext, CrateIDWrapper}; -use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; +pub use compile_new::{CompilerContext, CrateIDWrapper, compile_contract_, compile_program_}; +use wasm_bindgen::{JsValue, prelude::wasm_bindgen}; #[derive(Serialize, Deserialize)] pub struct BuildInfo { diff --git a/docs/docs/noir/concepts/data_types/integers.md b/docs/docs/noir/concepts/data_types/integers.md index b8a5d498029..ff3fafa1f90 100644 --- a/docs/docs/noir/concepts/data_types/integers.md +++ b/docs/docs/noir/concepts/data_types/integers.md @@ -58,54 +58,6 @@ fn main(x: i16, y: i16) { Modulo operation is defined for negative integers thanks to integer division, so that the equality `x = (x/y)*y + (x%y)` holds. -## 128 bits Unsigned Integers - -The built-in structure `U128` allows you to use 128-bit unsigned integers almost like a native integer type. However, there are some differences to keep in mind: -- You cannot cast between a native integer and `U128` -- There is a higher performance cost when using `U128`, compared to a native type. - -Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. `from_integer` also accepts the `Field` type as input. - -```rust -fn main() { - let x = U128::from_integer(23); - let y = U128::from_hex("0x7"); - let z = x + y; - assert(z.to_integer() == 30); -} -``` - -`U128` is implemented with two 64 bits limbs, representing the low and high bits, which explains the performance cost. You should expect `U128` to be twice more costly for addition and four times more costly for multiplication. -You can construct a U128 from its limbs: -```rust -fn main(x: u64, y: u64) { - let z = U128::from_u64s_be(x,y); - assert(z.hi == x as Field); - assert(z.lo == y as Field); -} -``` - -Note that the limbs are stored as Field elements in order to avoid unnecessary conversions. -Apart from this, most operations will work as usual: - -```rust -fn main(x: U128, y: U128) { - // multiplication - let c = x * y; - // addition and subtraction - let c = c - x + y; - // division - let c = x / y; - // bit operation; - let c = x & y | y; - // bit shift - let c = x << y; - // comparisons; - let c = x < y; - let c = x == y; -} -``` - ## Overflows Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: diff --git a/docs/docs/noir/concepts/traits.md b/docs/docs/noir/concepts/traits.md index 17cc04a9751..af5b396bfb8 100644 --- a/docs/docs/noir/concepts/traits.md +++ b/docs/docs/noir/concepts/traits.md @@ -153,6 +153,37 @@ fn main() { } ``` +## As Trait Syntax + +Rarely to call a method it may not be sufficient to use the general method call syntax of `obj.method(args)`. +One case where this may happen is if there are two traits in scope which both define a method with the same name. +For example: + +```rust +trait Foo { fn bar(); } +trait Foo2 { fn bar(); } + +fn example() + where T: Foo + Foo2 +{ + // How to call Foo::bar and Foo2::bar? +} +``` + +In the above example we have both `Foo` and `Foo2` which define a `bar` method. The normal way to resolve +this would be to use the static method syntax `Foo::bar(object)` but there is no object in this case and +`Self` does not appear in the type signature of `bar` at all so we would not know which impl to choose. +For these situations there is the "as trait" syntax: `::method(object, args...)` + +```rust +fn example() + where T: Foo + Foo2 +{ + ::bar(); + ::bar(); +} +``` + ## Generic Implementations You can add generics to a trait implementation by adding the generic list after the `impl` keyword: diff --git a/docs/docs/noir/standard_library/traits.md b/docs/docs/noir/standard_library/traits.md index e6f6f80ff03..ed923c0707a 100644 --- a/docs/docs/noir/standard_library/traits.md +++ b/docs/docs/noir/standard_library/traits.md @@ -71,7 +71,7 @@ As a general rule of thumb, `From` may be implemented in the [situations where i - The conversion is *infallible*: Noir does not provide an equivalent to Rust's `TryFrom`, if the conversion can fail then provide a named method instead. - The conversion is *lossless*: semantically, it should not lose or discard information. For example, `u32: From` can losslessly convert any `u16` into a valid `u32` such that the original `u16` can be recovered. On the other hand, `u16: From` should not be implemented as `2**16` is a `u32` which cannot be losslessly converted into a `u16`. - The conversion is *value-preserving*: the conceptual kind and meaning of the resulting value is the same, even though the Noir type and technical representation might be different. While it's possible to infallibly and losslessly convert a `u8` into a `str<2>` hex representation, `4u8` and `"04"` are too different for `str<2>: From` to be implemented. -- The conversion is *obvious*: it's the only reasonable conversion between the two types. If there's ambiguity on how to convert between them such that the same input could potentially map to two different values then a named method should be used. For instance rather than implementing `U128: From<[u8; 16]>`, the methods `U128::from_le_bytes` and `U128::from_be_bytes` are used as otherwise the endianness of the array would be ambiguous, resulting in two potential values of `U128` from the same byte array. +- The conversion is *obvious*: it's the only reasonable conversion between the two types. If there's ambiguity on how to convert between them such that the same input could potentially map to two different values then a named method should be used. For instance rather than implementing `u128: From<[u8; 16]>`, the methods `u128::from_le_bytes` and `u128::from_be_bytes` are used as otherwise the endianness of the array would be ambiguous, resulting in two potential values of `u128` from the same byte array. One additional recommendation specific to Noir is: - The conversion is *efficient*: it's relatively cheap to convert between the two types. Due to being a ZK DSL, it's more important to avoid unnecessary computation compared to Rust. If the implementation of `From` would encourage users to perform unnecessary conversion, resulting in additional proving time, then it may be preferable to expose functionality such that this conversion may be avoided. diff --git a/docs/docs/tooling/security.md b/docs/docs/tooling/security.md index e14481efc31..8a09d231a7d 100644 --- a/docs/docs/tooling/security.md +++ b/docs/docs/tooling/security.md @@ -39,7 +39,7 @@ Here, the results of `factor` are two elements of the returned array. The value This pass checks if the constraint coverage of Brillig calls is sufficient in these terms. -The check is at the moment disabled by default due to performance concerns and can be enabled by passing the `--enable-brillig-constraints-check` option to `nargo`. +The check is enabled by default and can be disabled by passing the `--skip-brillig-constraints-check` option to `nargo`. #### Lookback option diff --git a/noir_stdlib/src/hash/mod.nr b/noir_stdlib/src/hash/mod.nr index 1ded89ec80d..35a811c4570 100644 --- a/noir_stdlib/src/hash/mod.nr +++ b/noir_stdlib/src/hash/mod.nr @@ -9,7 +9,6 @@ use crate::embedded_curve_ops::{ EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return, }; use crate::meta::derive_via; -use crate::uint128::U128; // Kept for backwards compatibility pub use sha256::{digest, sha256, sha256_compression, sha256_var}; @@ -302,16 +301,6 @@ impl Hash for () { {} } -impl Hash for U128 { - fn hash(self, state: &mut H) - where - H: Hasher, - { - H::write(state, self.lo as Field); - H::write(state, self.hi as Field); - } -} - impl Hash for [T; N] where T: Hash, diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index d5c360792d9..8a8a4abd0ef 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -19,7 +19,6 @@ pub mod cmp; pub mod ops; pub mod default; pub mod prelude; -pub mod uint128; pub mod runtime; pub mod meta; pub mod append; @@ -121,8 +120,46 @@ where pub fn as_witness(x: Field) {} mod tests { + use super::wrapping_mul; + #[test(should_fail_with = "custom message")] fn test_static_assert_custom_message() { super::static_assert(1 == 2, "custom message"); } + + #[test(should_fail)] + fn test_wrapping_mul() { + // This currently fails. + // See: https://github.com/noir-lang/noir/issues/7528 + let zero: u128 = 0; + let one: u128 = 1; + let two_pow_64: u128 = 0x10000000000000000; + let u128_max: u128 = 0xffffffffffffffffffffffffffffffff; + + // 1*0==0 + assert_eq(zero, wrapping_mul(zero, one)); + + // 0*1==0 + assert_eq(zero, wrapping_mul(one, zero)); + + // 1*1==1 + assert_eq(one, wrapping_mul(one, one)); + + // 0 * ( 1 << 64 ) == 0 + assert_eq(zero, wrapping_mul(zero, two_pow_64)); + + // ( 1 << 64 ) * 0 == 0 + assert_eq(zero, wrapping_mul(two_pow_64, zero)); + + // 1 * ( 1 << 64 ) == 1 << 64 + assert_eq(two_pow_64, wrapping_mul(two_pow_64, one)); + + // ( 1 << 64 ) * 1 == 1 << 64 + assert_eq(two_pow_64, wrapping_mul(one, two_pow_64)); + + // ( 1 << 64 ) * ( 1 << 64 ) == 1 << 64 + assert_eq(zero, wrapping_mul(two_pow_64, two_pow_64)); + // -1 * -1 == 1 + assert_eq(one, wrapping_mul(u128_max, u128_max)); + } } diff --git a/noir_stdlib/src/prelude.nr b/noir_stdlib/src/prelude.nr index a4a6c35b615..7aa60456b6d 100644 --- a/noir_stdlib/src/prelude.nr +++ b/noir_stdlib/src/prelude.nr @@ -7,4 +7,3 @@ pub use crate::default::Default; pub use crate::meta::{derive, derive_via}; pub use crate::option::Option; pub use crate::panic::panic; -pub use crate::uint128::U128; diff --git a/noir_stdlib/src/uint128.nr b/noir_stdlib/src/uint128.nr deleted file mode 100644 index f41958e0e30..00000000000 --- a/noir_stdlib/src/uint128.nr +++ /dev/null @@ -1,572 +0,0 @@ -use crate::cmp::{Eq, Ord, Ordering}; -use crate::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub}; -use crate::static_assert; -use super::{convert::AsPrimitive, default::Default}; - -global pow64: Field = 18446744073709551616; //2^64; -global pow63: Field = 9223372036854775808; // 2^63; -pub struct U128 { - pub(crate) lo: Field, - pub(crate) hi: Field, -} - -impl U128 { - - pub fn from_u64s_le(lo: u64, hi: u64) -> U128 { - // in order to handle multiplication, we need to represent the product of two u64 without overflow - assert(crate::field::modulus_num_bits() as u32 > 128); - U128 { lo: lo as Field, hi: hi as Field } - } - - pub fn from_u64s_be(hi: u64, lo: u64) -> U128 { - U128::from_u64s_le(lo, hi) - } - - pub fn zero() -> U128 { - U128 { lo: 0, hi: 0 } - } - - pub fn one() -> U128 { - U128 { lo: 1, hi: 0 } - } - pub fn from_le_bytes(bytes: [u8; 16]) -> U128 { - let mut lo = 0; - let mut base = 1; - for i in 0..8 { - lo += (bytes[i] as Field) * base; - base *= 256; - } - let mut hi = 0; - base = 1; - for i in 8..16 { - hi += (bytes[i] as Field) * base; - base *= 256; - } - U128 { lo, hi } - } - - pub fn to_be_bytes(self: Self) -> [u8; 16] { - let lo: [u8; 8] = self.lo.to_be_bytes(); - let hi: [u8; 8] = self.hi.to_be_bytes(); - let mut bytes = [0; 16]; - for i in 0..8 { - bytes[i] = hi[i]; - bytes[i + 8] = lo[i]; - } - bytes - } - - pub fn to_le_bytes(self: Self) -> [u8; 16] { - let lo: [u8; 8] = self.lo.to_le_bytes(); - let hi: [u8; 8] = self.hi.to_le_bytes(); - let mut bytes = [0; 16]; - for i in 0..8 { - bytes[i] = lo[i]; - bytes[i + 8] = hi[i]; - } - bytes - } - - pub fn from_hex(hex: str) -> U128 { - let bytes = hex.as_bytes(); - // string must starts with "0x" - assert((bytes[0] == 48) & (bytes[1] == 120), "Invalid hexadecimal string"); - static_assert(N < 35, "Input does not fit into a U128"); - - let mut lo = 0; - let mut hi = 0; - let mut base = 1; - if N <= 18 { - for i in 0..N - 2 { - lo += U128::decode_ascii(bytes[N - i - 1]) * base; - base = base * 16; - } - } else { - for i in 0..16 { - lo += U128::decode_ascii(bytes[N - i - 1]) * base; - base = base * 16; - } - base = 1; - for i in 17..N - 1 { - hi += U128::decode_ascii(bytes[N - i]) * base; - base = base * 16; - } - } - U128 { lo: lo as Field, hi: hi as Field } - } - - unconstrained fn unconstrained_check_is_upper_ascii(ascii: u8) -> bool { - ((ascii >= 65) & (ascii <= 90)) // Between 'A' and 'Z' - } - - pub(crate) fn decode_ascii(ascii: u8) -> Field { - ( - if ascii < 58 { - ascii - 48 - } else { - // Safety: optionally adds 32 and then check (below) the result is in 'a..f' range - let ascii = - ascii + 32 * (unsafe { U128::unconstrained_check_is_upper_ascii(ascii) as u8 }); - assert(ascii >= 97); // enforce >= 'a' - assert(ascii <= 102); // enforce <= 'f' - ascii - 87 - } - ) as Field - } - - // TODO: Replace with a faster version. - // A circuit that uses this function can be slow to compute - // (we're doing up to 127 calls to compute the quotient) - unconstrained fn unconstrained_div(self: Self, b: U128) -> (U128, U128) { - if b == U128::zero() { - // Return 0,0 to avoid eternal loop - (U128::zero(), U128::zero()) - } else if self < b { - (U128::zero(), self) - } else if self == b { - (U128::one(), U128::zero()) - } else { - let (q, r) = if b.hi as u64 >= pow63 as u64 { - // The result of multiplication by 2 would overflow - (U128::zero(), self) - } else { - self.unconstrained_div(b * U128::from_u64s_le(2, 0)) - }; - let q_mul_2 = q * U128::from_u64s_le(2, 0); - if r < b { - (q_mul_2, r) - } else { - (q_mul_2 + U128::one(), r - b) - } - } - } - - pub fn from_integer(i: T) -> U128 - where - T: AsPrimitive, - { - let f = i.as_(); - // Reject values which would overflow a u128 - f.assert_max_bit_size::<128>(); - let lo = f as u64 as Field; - let hi = (f - lo) / pow64; - U128 { lo, hi } - } - - pub fn to_integer(self) -> T - where - Field: AsPrimitive, - { - AsPrimitive::as_(self.lo + self.hi * pow64) - } - - fn wrapping_mul(self: Self, b: U128) -> U128 { - let low = self.lo * b.lo; - let lo = low as u64 as Field; - let carry = (low - lo) / pow64; - let high = self.lo * b.hi + self.hi * b.lo + carry; - let hi = high as u64 as Field; - U128 { lo, hi } - } -} - -impl Add for U128 { - fn add(self: Self, b: U128) -> U128 { - let low = self.lo + b.lo; - let lo = low as u64 as Field; - let carry = (low - lo) / pow64; - let high = self.hi + b.hi + carry; - let hi = high as u64 as Field; - assert(hi == high, "attempt to add with overflow"); - U128 { lo, hi } - } -} - -impl Sub for U128 { - fn sub(self: Self, b: U128) -> U128 { - let low = pow64 + self.lo - b.lo; - let lo = low as u64 as Field; - let borrow = (low == lo) as Field; - let high = self.hi - b.hi - borrow; - let hi = high as u64 as Field; - assert(hi == high, "attempt to subtract with underflow"); - U128 { lo, hi } - } -} - -impl Mul for U128 { - fn mul(self: Self, b: U128) -> U128 { - assert(self.hi * b.hi == 0, "attempt to multiply with overflow"); - let low = self.lo * b.lo; - let lo = low as u64 as Field; - let carry = (low - lo) / pow64; - let high = if crate::field::modulus_num_bits() as u32 > 196 { - (self.lo + self.hi) * (b.lo + b.hi) - low + carry - } else { - self.lo * b.hi + self.hi * b.lo + carry - }; - let hi = high as u64 as Field; - assert(hi == high, "attempt to multiply with overflow"); - U128 { lo, hi } - } -} - -impl Div for U128 { - fn div(self: Self, b: U128) -> U128 { - // Safety: euclidian division is asserted to be correct: assert(a == b * q + r); and assert(r < b); - // Furthermore, U128 addition and multiplication ensures that b * q + r does not overflow - unsafe { - let (q, r) = self.unconstrained_div(b); - let a = b * q + r; - assert_eq(self, a); - assert(r < b); - q - } - } -} - -impl Rem for U128 { - fn rem(self: Self, b: U128) -> U128 { - // Safety: cf div() above - unsafe { - let (q, r) = self.unconstrained_div(b); - let a = b * q + r; - assert_eq(self, a); - assert(r < b); - - r - } - } -} - -impl Eq for U128 { - fn eq(self: Self, b: U128) -> bool { - (self.lo == b.lo) & (self.hi == b.hi) - } -} - -impl Ord for U128 { - fn cmp(self, other: Self) -> Ordering { - let hi_ordering = (self.hi as u64).cmp((other.hi as u64)); - let lo_ordering = (self.lo as u64).cmp((other.lo as u64)); - - if hi_ordering == Ordering::equal() { - lo_ordering - } else { - hi_ordering - } - } -} - -impl Not for U128 { - fn not(self) -> U128 { - U128 { lo: (!(self.lo as u64)) as Field, hi: (!(self.hi as u64)) as Field } - } -} - -impl BitOr for U128 { - fn bitor(self, other: U128) -> U128 { - U128 { - lo: ((self.lo as u64) | (other.lo as u64)) as Field, - hi: ((self.hi as u64) | (other.hi as u64)) as Field, - } - } -} - -impl BitAnd for U128 { - fn bitand(self, other: U128) -> U128 { - U128 { - lo: ((self.lo as u64) & (other.lo as u64)) as Field, - hi: ((self.hi as u64) & (other.hi as u64)) as Field, - } - } -} - -impl BitXor for U128 { - fn bitxor(self, other: U128) -> U128 { - U128 { - lo: ((self.lo as u64) ^ (other.lo as u64)) as Field, - hi: ((self.hi as u64) ^ (other.hi as u64)) as Field, - } - } -} - -impl Shl for U128 { - fn shl(self, other: u8) -> U128 { - assert(other < 128, "attempt to shift left with overflow"); - let exp_bits: [u1; 7] = (other as Field).to_be_bits(); - - let mut r: Field = 2; - let mut y: Field = 1; - for i in 1..8 { - let bit = exp_bits[7 - i] as Field; - y = bit * (r * y) + (1 - bit) * y; - r *= r; - } - self.wrapping_mul(U128::from_integer(y)) - } -} - -impl Shr for U128 { - fn shr(self, other: u8) -> U128 { - assert(other < 128, "attempt to shift right with overflow"); - let exp_bits: [u1; 7] = (other as Field).to_be_bits(); - - let mut r: Field = 2; - let mut y: Field = 1; - for i in 1..8 { - let bit = exp_bits[7 - i] as Field; - y = bit * (r * y) + (1 - bit) * y; - r *= r; - } - self / U128::from_integer(y) - } -} - -impl Default for U128 { - fn default() -> Self { - U128::zero() - } -} - -mod tests { - use crate::default::Default; - use crate::ops::Not; - use crate::uint128::{pow63, pow64, U128}; - - #[test] - fn test_not(lo: u64, hi: u64) { - let num = U128::from_u64s_le(lo, hi); - let not_num = num.not(); - - assert_eq(not_num.hi, (hi.not() as Field)); - assert_eq(not_num.lo, (lo.not() as Field)); - - let not_not_num = not_num.not(); - assert_eq(num, not_not_num); - } - #[test] - fn test_construction() { - // Check little-endian u64 is inversed with big-endian u64 construction - let a = U128::from_u64s_le(2, 1); - let b = U128::from_u64s_be(1, 2); - assert_eq(a, b); - // Check byte construction is equivalent - let c = U128::from_le_bytes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); - let d = U128::from_u64s_le(0x0706050403020100, 0x0f0e0d0c0b0a0908); - assert_eq(c, d); - } - #[test] - fn test_byte_decomposition() { - let a = U128::from_u64s_le(0x0706050403020100, 0x0f0e0d0c0b0a0908); - // Get big-endian and little-endian byte decompostions - let le_bytes_a = a.to_le_bytes(); - let be_bytes_a = a.to_be_bytes(); - - // Check equivalence - for i in 0..16 { - assert_eq(le_bytes_a[i], be_bytes_a[15 - i]); - } - // Reconstruct U128 from byte decomposition - let b = U128::from_le_bytes(le_bytes_a); - // Check that it's the same element - assert_eq(a, b); - } - #[test] - fn test_hex_constuction() { - let a = U128::from_u64s_le(0x1, 0x2); - let b = U128::from_hex("0x20000000000000001"); - assert_eq(a, b); - - let c = U128::from_hex("0xffffffffffffffffffffffffffffffff"); - let d = U128::from_u64s_le(0xffffffffffffffff, 0xffffffffffffffff); - assert_eq(c, d); - - let e = U128::from_hex("0x00000000000000000000000000000000"); - let f = U128::from_u64s_le(0, 0); - assert_eq(e, f); - } - - // Ascii decode tests - - #[test] - fn test_ascii_decode_correct_range() { - // '0'..'9' range - for i in 0..10 { - let decoded = U128::decode_ascii(48 + i); - assert_eq(decoded, i as Field); - } - // 'A'..'F' range - for i in 0..6 { - let decoded = U128::decode_ascii(65 + i); - assert_eq(decoded, (i + 10) as Field); - } - // 'a'..'f' range - for i in 0..6 { - let decoded = U128::decode_ascii(97 + i); - assert_eq(decoded, (i + 10) as Field); - } - } - - #[test(should_fail)] - fn test_ascii_decode_range_less_than_48_fails_0() { - crate::println(U128::decode_ascii(0)); - } - #[test(should_fail)] - fn test_ascii_decode_range_less_than_48_fails_1() { - crate::println(U128::decode_ascii(47)); - } - - #[test(should_fail)] - fn test_ascii_decode_range_58_64_fails_0() { - let _ = U128::decode_ascii(58); - } - #[test(should_fail)] - fn test_ascii_decode_range_58_64_fails_1() { - let _ = U128::decode_ascii(64); - } - #[test(should_fail)] - fn test_ascii_decode_range_71_96_fails_0() { - let _ = U128::decode_ascii(71); - } - #[test(should_fail)] - fn test_ascii_decode_range_71_96_fails_1() { - let _ = U128::decode_ascii(96); - } - #[test(should_fail)] - fn test_ascii_decode_range_greater_than_102_fails() { - let _ = U128::decode_ascii(103); - } - - #[test(should_fail)] - fn test_ascii_decode_regression() { - // This code will actually fail because of ascii_decode, - // but in the past it was possible to create a value > (1<<128) - let a = U128::from_hex("0x~fffffffffffffffffffffffffffffff"); - let b: Field = a.to_integer(); - let c: [u8; 17] = b.to_le_bytes(); - assert(c[16] != 0); - } - - #[test] - fn test_unconstrained_div() { - // Test the potential overflow case - let a = U128::from_u64s_le(0x0, 0xffffffffffffffff); - let b = U128::from_u64s_le(0x0, 0xfffffffffffffffe); - let c = U128::one(); - let d = U128::from_u64s_le(0x0, 0x1); - // Safety: testing context - unsafe { - let (q, r) = a.unconstrained_div(b); - assert_eq(q, c); - assert_eq(r, d); - } - - let a = U128::from_u64s_le(2, 0); - let b = U128::one(); - // Check the case where a is a multiple of b - // Safety: testing context - unsafe { - let (c, d) = a.unconstrained_div(b); - assert_eq((c, d), (a, U128::zero())); - } - - // Check where b is a multiple of a - // Safety: testing context - unsafe { - let (c, d) = b.unconstrained_div(a); - assert_eq((c, d), (U128::zero(), b)); - } - - // Dividing by zero returns 0,0 - let a = U128::from_u64s_le(0x1, 0x0); - let b = U128::zero(); - // Safety: testing context - unsafe { - let (c, d) = a.unconstrained_div(b); - assert_eq((c, d), (U128::zero(), U128::zero())); - } - // Dividing 1<<127 by 1<<127 (special case) - let a = U128::from_u64s_le(0x0, pow63 as u64); - let b = U128::from_u64s_le(0x0, pow63 as u64); - // Safety: testing context - unsafe { - let (c, d) = a.unconstrained_div(b); - assert_eq((c, d), (U128::one(), U128::zero())); - } - } - - #[test] - fn integer_conversions() { - // Maximum - let start: Field = 0xffffffffffffffffffffffffffffffff; - let a = U128::from_integer(start); - let end = a.to_integer(); - assert_eq(start, end); - - // Minimum - let start: Field = 0x0; - let a = U128::from_integer(start); - let end = a.to_integer(); - assert_eq(start, end); - - // Low limb - let start: Field = 0xffffffffffffffff; - let a = U128::from_integer(start); - let end = a.to_integer(); - assert_eq(start, end); - - // High limb - let start: Field = 0xffffffffffffffff0000000000000000; - let a = U128::from_integer(start); - let end = a.to_integer(); - assert_eq(start, end); - } - - #[test] - fn integer_conversions_fuzz(lo: u64, hi: u64) { - let start: Field = (lo as Field) + pow64 * (hi as Field); - let a = U128::from_integer(start); - let end = a.to_integer(); - assert_eq(start, end); - } - - #[test] - fn test_wrapping_mul() { - // 1*0==0 - assert_eq(U128::zero(), U128::zero().wrapping_mul(U128::one())); - - // 0*1==0 - assert_eq(U128::zero(), U128::one().wrapping_mul(U128::zero())); - - // 1*1==1 - assert_eq(U128::one(), U128::one().wrapping_mul(U128::one())); - - // 0 * ( 1 << 64 ) == 0 - assert_eq(U128::zero(), U128::zero().wrapping_mul(U128::from_u64s_le(0, 1))); - - // ( 1 << 64 ) * 0 == 0 - assert_eq(U128::zero(), U128::from_u64s_le(0, 1).wrapping_mul(U128::zero())); - - // 1 * ( 1 << 64 ) == 1 << 64 - assert_eq(U128::from_u64s_le(0, 1), U128::from_u64s_le(0, 1).wrapping_mul(U128::one())); - - // ( 1 << 64 ) * 1 == 1 << 64 - assert_eq(U128::from_u64s_le(0, 1), U128::one().wrapping_mul(U128::from_u64s_le(0, 1))); - - // ( 1 << 64 ) * ( 1 << 64 ) == 1 << 64 - assert_eq(U128::zero(), U128::from_u64s_le(0, 1).wrapping_mul(U128::from_u64s_le(0, 1))); - // -1 * -1 == 1 - assert_eq( - U128::one(), - U128::from_u64s_le(0xffffffffffffffff, 0xffffffffffffffff).wrapping_mul( - U128::from_u64s_le(0xffffffffffffffff, 0xffffffffffffffff), - ), - ); - } - - #[test] - fn test_default() { - assert_eq(U128::default(), U128::zero()); - } -} diff --git a/test_programs/compile_success_empty/comptime_as_field/src/main.nr b/test_programs/compile_success_empty/comptime_as_field/src/main.nr deleted file mode 100644 index f5871bbed81..00000000000 --- a/test_programs/compile_success_empty/comptime_as_field/src/main.nr +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - comptime { - let _: U128 = U128::from_integer(1); - } -} diff --git a/test_programs/compile_success_empty/comptime_as_field/Nargo.toml b/test_programs/compile_success_empty/comptime_as_primitive/Nargo.toml similarity index 100% rename from test_programs/compile_success_empty/comptime_as_field/Nargo.toml rename to test_programs/compile_success_empty/comptime_as_primitive/Nargo.toml diff --git a/test_programs/compile_success_empty/comptime_as_primitive/src/main.nr b/test_programs/compile_success_empty/comptime_as_primitive/src/main.nr new file mode 100644 index 00000000000..392ccf2ebfc --- /dev/null +++ b/test_programs/compile_success_empty/comptime_as_primitive/src/main.nr @@ -0,0 +1,7 @@ +fn main() { + comptime { + let x: u64 = 1; + let y = x as Field; + let _ = y as u128; + } +} diff --git a/test_programs/compile_success_empty/comptime_from_field/Nargo.toml b/test_programs/compile_success_empty/comptime_from_field/Nargo.toml deleted file mode 100644 index 38a46ba0dbe..00000000000 --- a/test_programs/compile_success_empty/comptime_from_field/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "comptime_from_field" -type = "bin" -authors = [""] - -[dependencies] diff --git a/test_programs/compile_success_empty/comptime_from_field/src/main.nr b/test_programs/compile_success_empty/comptime_from_field/src/main.nr deleted file mode 100644 index 028722b94b2..00000000000 --- a/test_programs/compile_success_empty/comptime_from_field/src/main.nr +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - comptime { - let _: Field = U128::from_hex("0x0").to_integer(); - } -} diff --git a/test_programs/execution_success/u128/Nargo.toml b/test_programs/execution_success/shift_right_overflow/Nargo.toml similarity index 63% rename from test_programs/execution_success/u128/Nargo.toml rename to test_programs/execution_success/shift_right_overflow/Nargo.toml index c1dcd84db04..a883299fbc2 100644 --- a/test_programs/execution_success/u128/Nargo.toml +++ b/test_programs/execution_success/shift_right_overflow/Nargo.toml @@ -1,6 +1,5 @@ [package] -name = "u128" +name = "shift_right_overflow" type = "bin" authors = [""] - [dependencies] diff --git a/test_programs/execution_success/shift_right_overflow/Prover.toml b/test_programs/execution_success/shift_right_overflow/Prover.toml new file mode 100644 index 00000000000..57cb8b2eac8 --- /dev/null +++ b/test_programs/execution_success/shift_right_overflow/Prover.toml @@ -0,0 +1 @@ +x = 9 diff --git a/test_programs/execution_success/shift_right_overflow/src/main.nr b/test_programs/execution_success/shift_right_overflow/src/main.nr new file mode 100644 index 00000000000..c5d23ab5cd9 --- /dev/null +++ b/test_programs/execution_success/shift_right_overflow/src/main.nr @@ -0,0 +1,5 @@ +fn main(x: u8) { + // This would previously overflow in ACIR. Now it returns zero. + let value = 1 >> x; + assert_eq(value, 0); +} diff --git a/test_programs/execution_success/u128/Prover.toml b/test_programs/execution_success/u128/Prover.toml deleted file mode 100644 index 961db9825a7..00000000000 --- a/test_programs/execution_success/u128/Prover.toml +++ /dev/null @@ -1,7 +0,0 @@ -x = "3" -y = "4" -z = "7" -hexa ="0x1f03a" -[big_int] -lo = 1 -hi = 2 \ No newline at end of file diff --git a/test_programs/execution_success/u128/src/main.nr b/test_programs/execution_success/u128/src/main.nr deleted file mode 100644 index 56ac5b995d9..00000000000 --- a/test_programs/execution_success/u128/src/main.nr +++ /dev/null @@ -1,41 +0,0 @@ -fn main(mut x: u32, y: u32, z: u32, big_int: U128, hexa: str<7>) { - let a = U128::from_u64s_le(x as u64, x as u64); - let b = U128::from_u64s_le(y as u64, x as u64); - let c = a + b; - assert(c.lo == z as Field); - assert(c.hi == 2 * x as Field); - assert(U128::from_hex(hexa).lo == 0x1f03a); - let t1 = U128::from_hex("0x9d9c7a87771f03a23783f9d9c7a8777"); - let t2 = U128::from_hex("0x45a26c708BFCF39041"); - let t = t1 + t2; - assert(t.lo == 0xc5e4b029996e17b8); - assert(t.hi == 0x09d9c7a87771f07f); - let t3 = U128::from_le_bytes(t.to_le_bytes()); - assert(t == t3); - - let t4 = t - t2; - assert(t4 == t1); - - let t5 = U128::from_u64s_le(0, 1); - let t6 = U128::from_u64s_le(1, 0); - assert((t5 - t6).hi == 0); - - assert( - (U128::from_hex("0x71f03a23783f9d9c7a8777") * U128::from_hex("0x8BFCF39041")).hi - == U128::from_hex("0x3e4e0471b873470e247c824e61445537").hi, - ); - let q = U128::from_hex("0x3e4e0471b873470e247c824e61445537") / U128::from_hex("0x8BFCF39041"); - assert(q == U128::from_hex("0x71f03a23783f9d9c7a8777")); - - assert(big_int.hi == 2); - - let mut small_int = U128::from_integer(x); - assert(small_int.lo == x as Field); - assert(x == small_int.to_integer()); - let shift = small_int << (x as u8); - assert(shift == U128::from_integer(x << (x as u8))); - assert(shift >> (x as u8) == small_int); - assert(shift >> 127 == U128::from_integer(0)); - assert(shift << 127 == U128::from_integer(0)); - assert(U128::from_integer(3).to_integer() == 3); -} diff --git a/test_programs/noir_test_success/global_eval/src/main.nr b/test_programs/noir_test_success/global_eval/src/main.nr index 87a2d50a916..da962bf5203 100644 --- a/test_programs/noir_test_success/global_eval/src/main.nr +++ b/test_programs/noir_test_success/global_eval/src/main.nr @@ -1,20 +1,9 @@ -use std::uint128::U128; - // These definitions require `to_be_bits` and `to_le_bits` to be supported at comptime. global BITS_BE_13: [u1; 4] = (13 as Field).to_be_bits(); global BITS_LE_13: [u1; 4] = (13 as Field).to_le_bits(); -// Examples from #6691 which use the above behind the scenes. -global POW64_A: Field = 2.pow_32(64); -global POW64_B: Field = (U128::one() << 64).to_integer(); - #[test] fn test_be_and_le_bits() { assert_eq(BITS_BE_13, [1, 1, 0, 1]); assert_eq(BITS_LE_13, [1, 0, 1, 1]); } - -#[test] -fn test_pow64() { - assert_eq(POW64_A, POW64_B); -} diff --git a/tooling/acvm_cli/src/cli/execute_cmd.rs b/tooling/acvm_cli/src/cli/execute_cmd.rs index 6f6fba7cd1e..c1d4533230e 100644 --- a/tooling/acvm_cli/src/cli/execute_cmd.rs +++ b/tooling/acvm_cli/src/cli/execute_cmd.rs @@ -1,14 +1,14 @@ use std::io::{self, Write}; use std::path::PathBuf; +use acir::FieldElement; use acir::circuit::Program; use acir::native_types::{WitnessMap, WitnessStack}; -use acir::FieldElement; use bn254_blackbox_solver::Bn254BlackBoxSolver; use clap::Args; use nargo::PrintOutput; -use nargo::{foreign_calls::DefaultForeignCallBuilder, ops::execute_program}; +use nargo::foreign_calls::DefaultForeignCallBuilder; use noir_artifact_cli::errors::CliError; use noir_artifact_cli::fs::artifact::read_bytecode_from_file; use noir_artifact_cli::fs::witness::save_witness_to_dir; @@ -56,7 +56,7 @@ fn run_command(args: ExecuteCommand) -> Result { )?; if args.output_witness.is_some() { save_witness_to_dir( - output_witness, + &output_witness, &args.output_witness.unwrap(), &args.working_directory, )?; @@ -80,7 +80,8 @@ pub(crate) fn execute_program_from_witness( ) -> Result, CliError> { let program: Program = Program::deserialize_program(bytecode).map_err(CliError::CircuitDeserializationError)?; - execute_program( + + nargo::ops::execute_program( &program, inputs_map, &Bn254BlackBoxSolver(pedantic_solving), diff --git a/tooling/acvm_cli/src/fs/witness.rs b/tooling/acvm_cli/src/fs/witness.rs index 5c2d2a9ad05..d1b88758cc7 100644 --- a/tooling/acvm_cli/src/fs/witness.rs +++ b/tooling/acvm_cli/src/fs/witness.rs @@ -1,8 +1,8 @@ //! These witness functions are only used by the ACVM CLI and we'll most likely deprecate them. use std::{collections::BTreeMap, path::Path}; -use acir::{native_types::Witness, FieldElement}; -use acvm::acir::{native_types::WitnessMap, AcirField}; +use acir::{FieldElement, native_types::Witness}; +use acvm::acir::{AcirField, native_types::WitnessMap}; use noir_artifact_cli::errors::{CliError, FilesystemError}; diff --git a/tooling/acvm_cli/src/main.rs b/tooling/acvm_cli/src/main.rs index a30360a947c..8f9edc48f32 100644 --- a/tooling/acvm_cli/src/main.rs +++ b/tooling/acvm_cli/src/main.rs @@ -8,7 +8,7 @@ mod cli; use std::env; use tracing_appender::rolling; -use tracing_subscriber::{fmt::format::FmtSpan, EnvFilter}; +use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan}; mod fs; diff --git a/tooling/artifact_cli/src/bin/execute.rs b/tooling/artifact_cli/src/bin/execute.rs index b66177a3d57..8bca901e485 100644 --- a/tooling/artifact_cli/src/bin/execute.rs +++ b/tooling/artifact_cli/src/bin/execute.rs @@ -1,10 +1,10 @@ #![forbid(unsafe_code)] #![warn(unreachable_pub)] -use clap::{command, Parser, Subcommand}; +use clap::{Parser, Subcommand, command}; use color_eyre::eyre; use const_format::formatcp; -use tracing_subscriber::{fmt::format::FmtSpan, EnvFilter}; +use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan}; use noir_artifact_cli::commands::execute_cmd; diff --git a/tooling/artifact_cli/src/commands/execute_cmd.rs b/tooling/artifact_cli/src/commands/execute_cmd.rs index 9a117329c15..df5d469e75b 100644 --- a/tooling/artifact_cli/src/commands/execute_cmd.rs +++ b/tooling/artifact_cli/src/commands/execute_cmd.rs @@ -1,18 +1,15 @@ -use std::{collections::BTreeMap, path::PathBuf}; +use std::path::PathBuf; -use acir::{circuit::Program, native_types::WitnessStack, FieldElement}; use bn254_blackbox_solver::Bn254BlackBoxSolver; use clap::Args; -use color_eyre::eyre::{self, bail}; use crate::{ - errors::CliError, - fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}, Artifact, + errors::CliError, + execution::{self, ExecutionResults}, }; -use nargo::{foreign_calls::DefaultForeignCallBuilder, NargoError, PrintOutput}; -use noirc_abi::{input_parser::InputValue, Abi}; -use noirc_artifacts::debug::DebugArtifact; +use nargo::{PrintOutput, foreign_calls::DefaultForeignCallBuilder}; +use noirc_driver::CompiledProgram; use super::parse_and_normalize_path; @@ -21,106 +18,84 @@ use super::parse_and_normalize_path; pub struct ExecuteCommand { /// Path to the JSON build artifact (either a program or a contract). #[clap(long, short, value_parser = parse_and_normalize_path)] - artifact_path: PathBuf, + pub artifact_path: PathBuf, /// Path to the Prover.toml file which contains the inputs and the /// optional return value in ABI format. #[clap(long, short, value_parser = parse_and_normalize_path)] - prover_file: PathBuf, + pub prover_file: PathBuf, /// Path to the directory where the output witness should be saved. /// If empty then the results are discarded. #[clap(long, short, value_parser = parse_and_normalize_path)] - output_dir: Option, + pub output_dir: Option, /// Write the execution witness to named file /// /// Defaults to the name of the circuit being executed. #[clap(long, short)] - witness_name: Option, + pub witness_name: Option, /// Name of the function to execute, if the artifact is a contract. #[clap(long)] - contract_fn: Option, + pub contract_fn: Option, /// JSON RPC url to solve oracle calls. #[clap(long)] - oracle_resolver: Option, + pub oracle_resolver: Option, /// Use pedantic ACVM solving, i.e. double-check some black-box function assumptions when solving. #[clap(long, default_value_t = false)] - pedantic_solving: bool, + pub pedantic_solving: bool, } -pub fn run(args: ExecuteCommand) -> eyre::Result<()> { +pub fn run(args: ExecuteCommand) -> Result<(), CliError> { let artifact = Artifact::read_from_file(&args.artifact_path)?; + let artifact_name = args.artifact_path.file_stem().and_then(|s| s.to_str()).unwrap_or_default(); - let circuit = match artifact { - Artifact::Program(program) => Circuit { - name: None, - abi: program.abi, - bytecode: program.bytecode, - debug_symbols: program.debug_symbols, - file_map: program.file_map, - }, + let (circuit, circuit_name): (CompiledProgram, String) = match artifact { + Artifact::Program(program) => (program.into(), artifact_name.to_string()), Artifact::Contract(contract) => { - let names = - contract.functions.iter().map(|f| f.name.clone()).collect::>().join(","); + let names = || contract.functions.iter().map(|f| f.name.clone()).collect::>(); let Some(ref name) = args.contract_fn else { - bail!("--contract-fn missing; options: [{names}]"); + return Err(CliError::MissingContractFn { names: names() }); }; - let Some(function) = contract.functions.into_iter().find(|f| f.name == *name) else { - bail!("unknown --contract-fn '{name}'; options: [{names}]"); + let Some(program) = contract.function_as_compiled_program(name) else { + return Err(CliError::UnknownContractFn { name: name.clone(), names: names() }); }; - Circuit { - name: Some(name.clone()), - abi: function.abi, - bytecode: function.bytecode, - debug_symbols: function.debug_symbols, - file_map: contract.file_map, - } + (program, format!("{artifact_name}::{name}")) } }; match execute(&circuit, &args) { - Ok(solved) => { - save_witness(circuit, args, solved)?; - } - Err(CliError::CircuitExecutionError(err)) => { - show_diagnostic(circuit, err); + Ok(results) => { + execution::save_and_check_witness( + &circuit, + results, + &circuit_name, + args.output_dir.as_deref(), + args.witness_name.as_deref(), + )?; } Err(e) => { - bail!("failed to execute the circuit: {e}"); + if let CliError::CircuitExecutionError(ref err) = e { + execution::show_diagnostic(&circuit, err); + } + // Still returning the error to facilitate command forwarding, to indicate that the command failed. + return Err(e); } } Ok(()) } -/// Parameters necessary to execute a circuit, display execution failures, etc. -struct Circuit { - name: Option, - abi: Abi, - bytecode: Program, - debug_symbols: noirc_errors::debug_info::ProgramDebugInfo, - file_map: BTreeMap, -} - -struct SolvedWitnesses { - expected_return: Option, - actual_return: Option, - witness_stack: WitnessStack, -} - /// Execute a circuit and return the output witnesses. -fn execute(circuit: &Circuit, args: &ExecuteCommand) -> Result { - let (input_map, expected_return) = read_inputs_from_file(&args.prover_file, &circuit.abi)?; - - let initial_witness = circuit.abi.encode(&input_map, None)?; - +fn execute(circuit: &CompiledProgram, args: &ExecuteCommand) -> Result { // TODO: Build a custom foreign call executor that reads from the Oracle transcript, - // and use it as a base for the default executor; see `DefaultForeignCallBuilder::build_with_base` + // and use it as a base for the default executor. Using it as the innermost rather + // than top layer so that any extra `print` added for debugging is handled by the + // default, rather than trying to match it to the transcript. let mut foreign_call_executor = DefaultForeignCallBuilder { output: PrintOutput::Stdout, enable_mocks: false, @@ -130,80 +105,7 @@ fn execute(circuit: &Circuit, args: &ExecuteCommand) -> Result) { - if let Some(diagnostic) = nargo::errors::try_to_diagnose_runtime_error( - &err, - &circuit.abi, - &circuit.debug_symbols.debug_infos, - ) { - let debug_artifact = DebugArtifact { - debug_symbols: circuit.debug_symbols.debug_infos, - file_map: circuit.file_map, - }; - diagnostic.report(&debug_artifact, false); - } -} - -/// Print information about the witness and compare to expectations, -/// returning errors if something isn't right. -fn save_witness( - circuit: Circuit, - args: ExecuteCommand, - solved: SolvedWitnesses, -) -> eyre::Result<()> { - let artifact = args.artifact_path.file_stem().and_then(|s| s.to_str()).unwrap_or_default(); - let name = circuit - .name - .as_ref() - .map(|name| format!("{artifact}.{name}")) - .unwrap_or_else(|| artifact.to_string()); - - println!("[{}] Circuit witness successfully solved", name); - - if let Some(ref witness_dir) = args.output_dir { - let witness_path = save_witness_to_dir( - solved.witness_stack, - &args.witness_name.unwrap_or_else(|| name.clone()), - witness_dir, - )?; - println!("[{}] Witness saved to {}", name, witness_path.display()); - } - - // Check that the circuit returned a non-empty result if the ABI expects a return value. - if let Some(ref expected) = circuit.abi.return_type { - if solved.actual_return.is_none() { - bail!("Missing return witness; expected a value of type {expected:?}"); - } - } - - // Check that if the prover file contained a `return` entry then that's what we got. - if let Some(expected) = solved.expected_return { - match solved.actual_return { - None => { - bail!("Missing return witness;\nexpected:\n{expected:?}"); - } - Some(actual) if actual != expected => { - bail!("Unexpected return witness;\nexpected:\n{expected:?}\ngot:\n{actual:?}"); - } - _ => {} - } - } - - Ok(()) + execution::execute(circuit, &blackbox_solver, &mut foreign_call_executor, &args.prover_file) } diff --git a/tooling/artifact_cli/src/commands/mod.rs b/tooling/artifact_cli/src/commands/mod.rs index 78f3b19292f..9049b3695b7 100644 --- a/tooling/artifact_cli/src/commands/mod.rs +++ b/tooling/artifact_cli/src/commands/mod.rs @@ -1,3 +1,4 @@ +//! This module is for commands that we might want to invoke from `nargo` as-is. use std::path::PathBuf; use color_eyre::eyre; diff --git a/tooling/artifact_cli/src/errors.rs b/tooling/artifact_cli/src/errors.rs index 5f302f78695..6c87273cb37 100644 --- a/tooling/artifact_cli/src/errors.rs +++ b/tooling/artifact_cli/src/errors.rs @@ -1,6 +1,10 @@ use acir::FieldElement; use nargo::NargoError; -use noirc_abi::errors::{AbiError, InputParserError}; +use noirc_abi::{ + AbiReturnType, + errors::{AbiError, InputParserError}, + input_parser::InputValue, +}; use std::path::PathBuf; use thiserror::Error; @@ -61,4 +65,16 @@ pub enum CliError { #[error("Failed to serialize output witness: {0}")] OutputWitnessSerializationFailed(#[from] toml::ser::Error), + + #[error("Unexpected return value: expected {expected:?}; got {actual:?}")] + UnexpectedReturn { expected: InputValue, actual: Option }, + + #[error("Missing return witnesses; expected {expected:?}")] + MissingReturn { expected: AbiReturnType }, + + #[error("Missing contract function name; options: {names:?}")] + MissingContractFn { names: Vec }, + + #[error("Unknown contract function '{name}'; options: {names:?}")] + UnknownContractFn { name: String, names: Vec }, } diff --git a/tooling/artifact_cli/src/execution.rs b/tooling/artifact_cli/src/execution.rs new file mode 100644 index 00000000000..2e19ab55161 --- /dev/null +++ b/tooling/artifact_cli/src/execution.rs @@ -0,0 +1,135 @@ +use std::path::Path; + +use acir::{FieldElement, native_types::WitnessStack}; +use acvm::BlackBoxFunctionSolver; +use nargo::{NargoError, foreign_calls::ForeignCallExecutor}; +use noirc_abi::input_parser::InputValue; +use noirc_artifacts::debug::DebugArtifact; +use noirc_driver::CompiledProgram; + +use crate::{ + errors::CliError, + fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}, +}; + +/// Results of a circuit execution. +#[derive(Clone, Debug)] +pub struct ExecutionResults { + pub witness_stack: WitnessStack, + pub return_values: ReturnValues, +} + +/// The decoded `return` witnesses. +#[derive(Clone, Debug)] +pub struct ReturnValues { + /// The `return` value from the `Prover.toml` file, if present. + pub expected_return: Option, + /// The `return` value from the circuit execution. + pub actual_return: Option, +} + +/// Execute a circuit and return the output witnesses. +pub fn execute( + circuit: &CompiledProgram, + blackbox_solver: &B, + foreign_call_executor: &mut E, + prover_file: &Path, +) -> Result +where + B: BlackBoxFunctionSolver, + E: ForeignCallExecutor, +{ + let (input_map, expected_return) = read_inputs_from_file(prover_file, &circuit.abi)?; + + let initial_witness = circuit.abi.encode(&input_map, None)?; + + let witness_stack = nargo::ops::execute_program( + &circuit.program, + initial_witness, + blackbox_solver, + foreign_call_executor, + )?; + + let main_witness = + &witness_stack.peek().expect("Should have at least one witness on the stack").witness; + + let (_, actual_return) = circuit.abi.decode(main_witness)?; + + Ok(ExecutionResults { + witness_stack, + return_values: ReturnValues { actual_return, expected_return }, + }) +} + +/// Print an error stack trace, if possible. +pub fn show_diagnostic(circuit: &CompiledProgram, err: &NargoError) { + if let Some(diagnostic) = + nargo::errors::try_to_diagnose_runtime_error(err, &circuit.abi, &circuit.debug) + { + let debug_artifact = DebugArtifact { + debug_symbols: circuit.debug.clone(), + file_map: circuit.file_map.clone(), + }; + + diagnostic.report(&debug_artifact, false); + } +} + +/// Print some information and save the witness if an output directory is specified, +/// then checks if the expected return values were the ones we expected. +pub fn save_and_check_witness( + circuit: &CompiledProgram, + results: ExecutionResults, + circuit_name: &str, + witness_dir: Option<&Path>, + witness_name: Option<&str>, +) -> Result<(), CliError> { + println!("[{}] Circuit witness successfully solved", circuit_name); + // Save first, so that we can potentially look at the output if the expectations fail. + if let Some(witness_dir) = witness_dir { + save_witness(&results.witness_stack, circuit_name, witness_dir, witness_name)?; + } + check_witness(circuit, results.return_values) +} + +/// Save the witness stack to a file. +pub fn save_witness( + witness_stack: &WitnessStack, + circuit_name: &str, + witness_dir: &Path, + witness_name: Option<&str>, +) -> Result<(), CliError> { + let witness_name = witness_name.unwrap_or(circuit_name); + let witness_path = save_witness_to_dir(witness_stack, witness_name, witness_dir)?; + println!("[{}] Witness saved to {}", circuit_name, witness_path.display()); + Ok(()) +} + +/// Compare return values to expectations, returning errors if something unexpected was returned. +pub fn check_witness( + circuit: &CompiledProgram, + return_values: ReturnValues, +) -> Result<(), CliError> { + // Check that the circuit returned a non-empty result if the ABI expects a return value. + if let Some(ref expected) = circuit.abi.return_type { + if return_values.actual_return.is_none() { + return Err(CliError::MissingReturn { expected: expected.clone() }); + } + } + + // Check that if the prover file contained a `return` entry then that's what we got. + if let Some(expected) = return_values.expected_return { + match return_values.actual_return { + None => { + return Err(CliError::UnexpectedReturn { expected, actual: None }); + } + Some(actual) => { + if actual != expected { + return Err(CliError::UnexpectedReturn { expected, actual: Some(actual) }); + } + } + } + } + + Ok(()) +} diff --git a/tooling/artifact_cli/src/fs/artifact.rs b/tooling/artifact_cli/src/fs/artifact.rs index d4319e4cf0f..1a55764a9fe 100644 --- a/tooling/artifact_cli/src/fs/artifact.rs +++ b/tooling/artifact_cli/src/fs/artifact.rs @@ -1,8 +1,8 @@ use std::path::{Path, PathBuf}; use crate::{ - errors::{CliError, FilesystemError}, Artifact, + errors::{CliError, FilesystemError}, }; use noirc_artifacts::contract::ContractArtifact; use noirc_artifacts::program::ProgramArtifact; diff --git a/tooling/artifact_cli/src/fs/inputs.rs b/tooling/artifact_cli/src/fs/inputs.rs index f115af92041..753343af8c6 100644 --- a/tooling/artifact_cli/src/fs/inputs.rs +++ b/tooling/artifact_cli/src/fs/inputs.rs @@ -1,6 +1,6 @@ use noirc_abi::{ - input_parser::{Format, InputValue}, Abi, InputMap, MAIN_RETURN_NAME, + input_parser::{Format, InputValue}, }; use std::{collections::BTreeMap, path::Path}; diff --git a/tooling/artifact_cli/src/fs/witness.rs b/tooling/artifact_cli/src/fs/witness.rs index a669b0cd568..fee31ec1f22 100644 --- a/tooling/artifact_cli/src/fs/witness.rs +++ b/tooling/artifact_cli/src/fs/witness.rs @@ -1,13 +1,13 @@ use std::path::{Path, PathBuf}; -use acir::{native_types::WitnessStackError, FieldElement}; +use acir::{FieldElement, native_types::WitnessStackError}; use acvm::acir::native_types::WitnessStack; use crate::errors::{CliError, FilesystemError}; /// Write `witness.gz` to the output directory. pub fn save_witness_to_dir( - witnesses: WitnessStack, + witnesses: &WitnessStack, witness_name: &str, witness_dir: &Path, ) -> Result { diff --git a/tooling/artifact_cli/src/lib.rs b/tooling/artifact_cli/src/lib.rs index 2cd2341b7b7..ac4316f5801 100644 --- a/tooling/artifact_cli/src/lib.rs +++ b/tooling/artifact_cli/src/lib.rs @@ -2,6 +2,7 @@ use noirc_artifacts::{contract::ContractArtifact, program::ProgramArtifact}; pub mod commands; pub mod errors; +pub mod execution; pub mod fs; /// A parsed JSON build artifact. diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 1dbe9d11eee..79e03672e8d 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -5,22 +5,22 @@ use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap, WitnessStack}; use acvm::brillig_vm::MemoryValue; use acvm::pwg::{ - ACVMStatus, AcirCallWaitInfo, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, - OpcodeNotSolvable, StepResult, ACVM, + ACVM, ACVMStatus, AcirCallWaitInfo, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, + OpcodeNotSolvable, StepResult, }; use acvm::{BlackBoxFunctionSolver, FieldElement}; use codespan_reporting::files::{Files, SimpleFile}; use fm::FileId; -use nargo::errors::{ExecutionError, Location}; use nargo::NargoError; +use nargo::errors::{ExecutionError, Location}; use noirc_artifacts::debug::{DebugArtifact, StackFrame}; use noirc_driver::DebugFile; use thiserror::Error; use std::collections::BTreeMap; -use std::collections::{hash_set::Iter, HashSet}; +use std::collections::{HashSet, hash_set::Iter}; /// A Noir program is composed by /// `n` ACIR circuits @@ -960,13 +960,13 @@ mod tests { use crate::foreign_calls::DefaultDebugForeignCallExecutor; use acvm::{ acir::{ + AcirField, brillig::{HeapVector, IntegerBitSize}, circuit::{ brillig::{BrilligFunctionId, BrilligInputs, BrilligOutputs}, opcodes::{AcirFunctionId, BlockId, BlockType}, }, native_types::Expression, - AcirField, }, blackbox_solver::StubbedBlackBoxSolver, brillig_vm::brillig::{ diff --git a/tooling/debugger/src/dap.rs b/tooling/debugger/src/dap.rs index 0d2095954e0..1df27d8ea6f 100644 --- a/tooling/debugger/src/dap.rs +++ b/tooling/debugger/src/dap.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; use std::io::{Read, Write}; -use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::circuit::Circuit; +use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::native_types::WitnessMap; use acvm::{BlackBoxFunctionSolver, FieldElement}; use nargo::PrintOutput; @@ -466,14 +466,14 @@ impl<'a, R: Read, W: Write, B: BlackBoxFunctionSolver> DapSession< } fn map_source_breakpoints(&mut self, args: &SetBreakpointsArguments) -> Vec { - let Some(ref source) = &args.source.path else { + let Some(source) = &args.source.path else { return vec![]; }; let Some(file_id) = self.find_file_id(source) else { eprintln!("WARN: file ID for source {source} not found"); return vec![]; }; - let Some(ref breakpoints) = &args.breakpoints else { + let Some(breakpoints) = &args.breakpoints else { return vec![]; }; let mut breakpoints_to_set: Vec<(DebugLocation, i64)> = vec![]; diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index b92e22844ea..efae3df407a 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -1,13 +1,13 @@ use acvm::{ + AcirField, FieldElement, acir::brillig::{ForeignCallParam, ForeignCallResult}, pwg::ForeignCallWaitInfo, - AcirField, FieldElement, }; use nargo::{ + PrintOutput, foreign_calls::{ - layers::Layer, DefaultForeignCallBuilder, ForeignCallError, ForeignCallExecutor, + DefaultForeignCallBuilder, ForeignCallError, ForeignCallExecutor, layers::Layer, }, - PrintOutput, }; use noirc_artifacts::debug::{DebugArtifact, DebugVars, StackFrame}; use noirc_errors::debug_info::{DebugFnId, DebugVarId}; @@ -66,7 +66,7 @@ impl DefaultDebugForeignCallExecutor { pub fn from_artifact<'a>( output: PrintOutput<'a>, artifact: &DebugArtifact, - ) -> impl DebugForeignCallExecutor + 'a { + ) -> impl DebugForeignCallExecutor + use<'a> { let mut ex = Self::default(); ex.load_artifact(artifact); Self::make(output, ex) diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index e6edd652c0c..08156146985 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -1,12 +1,12 @@ use crate::context::{DebugCommandResult, DebugContext, DebugLocation}; +use acvm::AcirField; use acvm::acir::brillig::BitSize; use acvm::acir::circuit::brillig::{BrilligBytecode, BrilligFunctionId}; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap, WitnessStack}; -use acvm::brillig_vm::brillig::Opcode as BrilligOpcode; use acvm::brillig_vm::MemoryValue; -use acvm::AcirField; +use acvm::brillig_vm::brillig::Opcode as BrilligOpcode; use acvm::{BlackBoxFunctionSolver, FieldElement}; use nargo::{NargoError, PrintOutput}; use noirc_driver::CompiledProgram; @@ -14,7 +14,7 @@ use noirc_driver::CompiledProgram; use crate::foreign_calls::DefaultDebugForeignCallExecutor; use noirc_artifacts::debug::DebugArtifact; -use easy_repl::{command, CommandStatus, Repl}; +use easy_repl::{CommandStatus, Repl, command}; use noirc_printable_type::PrintableValueDisplay; use std::cell::RefCell; diff --git a/tooling/debugger/src/source_code_printer.rs b/tooling/debugger/src/source_code_printer.rs index 503db6d86e1..a756de8d98b 100644 --- a/tooling/debugger/src/source_code_printer.rs +++ b/tooling/debugger/src/source_code_printer.rs @@ -244,17 +244,17 @@ fn render_location<'a>( #[cfg(test)] mod tests { - use crate::source_code_printer::render_location; use crate::source_code_printer::PrintedLine::Content; + use crate::source_code_printer::render_location; use acvm::acir::circuit::OpcodeLocation; use fm::FileManager; use noirc_artifacts::debug::DebugArtifact; - use noirc_errors::{debug_info::DebugInfo, Location, Span}; + use noirc_errors::{Location, Span, debug_info::DebugInfo}; use std::collections::BTreeMap; use std::ops::Range; use std::path::Path; use std::path::PathBuf; - use tempfile::{tempdir, TempDir}; + use tempfile::{TempDir, tempdir}; // Returns the absolute path to the file fn create_dummy_file(dir: &TempDir, file_name: &Path) -> PathBuf { diff --git a/tooling/fuzzer/src/dictionary/mod.rs b/tooling/fuzzer/src/dictionary/mod.rs index 7fe1c4cd602..4f15a336a3e 100644 --- a/tooling/fuzzer/src/dictionary/mod.rs +++ b/tooling/fuzzer/src/dictionary/mod.rs @@ -6,16 +6,16 @@ use std::collections::HashSet; use acvm::{ + AcirField, acir::{ circuit::{ + Circuit, Opcode, Program, brillig::{BrilligBytecode, BrilligInputs}, opcodes::{BlackBoxFuncCall, ConstantOrWitnessEnum}, - Circuit, Opcode, Program, }, native_types::Expression, }, brillig_vm::brillig::Opcode as BrilligOpcode, - AcirField, }; /// Constructs a [HashSet] of values pulled from a [Program] which are likely to be correspond diff --git a/tooling/fuzzer/src/lib.rs b/tooling/fuzzer/src/lib.rs index 324be323fc2..471f3da88f6 100644 --- a/tooling/fuzzer/src/lib.rs +++ b/tooling/fuzzer/src/lib.rs @@ -4,11 +4,11 @@ //! Code is used under the MIT license. use acvm::{ + FieldElement, acir::{ circuit::Program, native_types::{WitnessMap, WitnessStack}, }, - FieldElement, }; use dictionary::build_dictionary_from_program; use noirc_abi::InputMap; diff --git a/tooling/fuzzer/src/strategies/int.rs b/tooling/fuzzer/src/strategies/int.rs index 22dded7c7b7..5fb8d469a92 100644 --- a/tooling/fuzzer/src/strategies/int.rs +++ b/tooling/fuzzer/src/strategies/int.rs @@ -54,20 +54,12 @@ impl IntStrategy { /// Maximum allowed positive number. fn type_max(&self) -> i128 { - if self.bits < 128 { - (1i128 << (self.bits - 1)) - 1 - } else { - i128::MAX - } + if self.bits < 128 { (1i128 << (self.bits - 1)) - 1 } else { i128::MAX } } /// Minimum allowed negative number. fn type_min(&self) -> i128 { - if self.bits < 128 { - -(1i128 << (self.bits - 1)) - } else { - i128::MIN - } + if self.bits < 128 { -(1i128 << (self.bits - 1)) } else { i128::MIN } } } diff --git a/tooling/fuzzer/src/strategies/mod.rs b/tooling/fuzzer/src/strategies/mod.rs index 99c7ca56f2e..4c8181ea804 100644 --- a/tooling/fuzzer/src/strategies/mod.rs +++ b/tooling/fuzzer/src/strategies/mod.rs @@ -4,7 +4,7 @@ use proptest::prelude::*; use acvm::{AcirField, FieldElement}; -use noirc_abi::{input_parser::InputValue, Abi, AbiType, InputMap, Sign}; +use noirc_abi::{Abi, AbiType, InputMap, Sign, input_parser::InputValue}; use std::collections::{BTreeMap, HashSet}; use uint::UintStrategy; diff --git a/tooling/fuzzer/src/strategies/uint.rs b/tooling/fuzzer/src/strategies/uint.rs index 402e6559752..904a5cef287 100644 --- a/tooling/fuzzer/src/strategies/uint.rs +++ b/tooling/fuzzer/src/strategies/uint.rs @@ -78,11 +78,7 @@ impl UintStrategy { /// Maximum integer that fits in the given bit width. fn type_max(&self) -> u128 { - if self.bits < 128 { - (1 << self.bits) - 1 - } else { - u128::MAX - } + if self.bits < 128 { (1 << self.bits) - 1 } else { u128::MAX } } } diff --git a/tooling/inspector/src/cli/info_cmd.rs b/tooling/inspector/src/cli/info_cmd.rs index 3db36425c7f..34107ebea3a 100644 --- a/tooling/inspector/src/cli/info_cmd.rs +++ b/tooling/inspector/src/cli/info_cmd.rs @@ -3,8 +3,7 @@ use std::path::PathBuf; use clap::Args; use color_eyre::eyre; use noir_artifact_cli::Artifact; -use noirc_artifacts::program::ProgramArtifact; -use noirc_artifacts_info::{count_opcodes_and_gates_in_program, show_info_report, InfoReport}; +use noirc_artifacts_info::{InfoReport, count_opcodes_and_gates_in_program, show_info_report}; #[derive(Debug, Clone, Args)] pub(crate) struct InfoCommand { @@ -39,19 +38,12 @@ pub(crate) fn run(args: InfoCommand) -> eyre::Result<()> { .into_iter() .filter(|f| args.contract_fn.as_ref().map(|n| *n == f.name).unwrap_or(true)) .map(|f| { - // We have to cheat to be able to call `count_opcodes_and_gates_in_program`. let package_name = format!("{}::{}", contract.name, f.name); - let program = ProgramArtifact { - noir_version: contract.noir_version.clone(), - hash: f.hash, - abi: f.abi, - bytecode: f.bytecode, - debug_symbols: f.debug_symbols, - file_map: contract.file_map.clone(), - names: f.names, - brillig_names: f.brillig_names, - }; - count_opcodes_and_gates_in_program(program, package_name, None) + let program = f.into_compiled_program( + contract.noir_version.clone(), + contract.file_map.clone(), + ); + count_opcodes_and_gates_in_program(program.into(), package_name, None) }) .collect::>(), }; diff --git a/tooling/inspector/src/cli/mod.rs b/tooling/inspector/src/cli/mod.rs index 8cce6ec3a6f..411f2076973 100644 --- a/tooling/inspector/src/cli/mod.rs +++ b/tooling/inspector/src/cli/mod.rs @@ -1,4 +1,4 @@ -use clap::{command, Parser, Subcommand}; +use clap::{Parser, Subcommand, command}; use color_eyre::eyre; use const_format::formatcp; diff --git a/tooling/lsp/src/attribute_reference_finder.rs b/tooling/lsp/src/attribute_reference_finder.rs index f8b4b823bb5..384c575f0c6 100644 --- a/tooling/lsp/src/attribute_reference_finder.rs +++ b/tooling/lsp/src/attribute_reference_finder.rs @@ -9,6 +9,7 @@ use std::collections::BTreeMap; use fm::FileId; use noirc_errors::Span; use noirc_frontend::{ + ParsedModule, ast::{AttributeTarget, Visitor}, graph::CrateId, hir::{ @@ -19,7 +20,6 @@ use noirc_frontend::{ parser::ParsedSubModule, token::MetaAttribute, usage_tracker::UsageTracker, - ParsedModule, }; use crate::modules::module_def_id_to_reference_id; diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index f705b53215b..784ac8cf93d 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -15,35 +15,35 @@ use std::{ use acvm::{BlackBoxFunctionSolver, FieldElement}; use async_lsp::{ - router::Router, AnyEvent, AnyNotification, AnyRequest, ClientSocket, Error, LspService, - ResponseError, + AnyEvent, AnyNotification, AnyRequest, ClientSocket, Error, LspService, ResponseError, + router::Router, }; -use fm::{codespan_files as files, FileManager}; +use fm::{FileManager, codespan_files as files}; use fxhash::FxHashSet; use lsp_types::{ + CodeLens, request::{ CodeActionRequest, Completion, DocumentSymbolRequest, HoverRequest, InlayHintRequest, PrepareRenameRequest, References, Rename, SignatureHelpRequest, }, - CodeLens, }; use nargo::{ package::{Package, PackageType}, parse_all, workspace::Workspace, }; -use nargo_toml::{find_file_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{file_manager_with_stdlib, prepare_crate, NOIR_ARTIFACT_VERSION_STRING}; +use nargo_toml::{PackageSelection, find_file_manifest, resolve_workspace_from_toml}; +use noirc_driver::{NOIR_ARTIFACT_VERSION_STRING, file_manager_with_stdlib, prepare_crate}; use noirc_frontend::{ + ParsedModule, graph::{CrateGraph, CrateId, CrateName}, hir::{ - def_map::{parse_file, CrateDefMap}, Context, FunctionNameMatch, ParsedFiles, + def_map::{CrateDefMap, parse_file}, }, node_interner::NodeInterner, parser::ParserError, usage_tracker::UsageTracker, - ParsedModule, }; use rayon::prelude::*; @@ -52,12 +52,11 @@ use notifications::{ on_did_open_text_document, on_did_save_text_document, on_exit, on_initialized, }; use requests::{ - on_code_action_request, on_code_lens_request, on_completion_request, + LspInitializationOptions, on_code_action_request, on_code_lens_request, on_completion_request, on_document_symbol_request, on_formatting, on_goto_declaration_request, on_goto_definition_request, on_goto_type_definition_request, on_hover_request, on_initialize, on_inlay_hint_request, on_prepare_rename_request, on_references_request, on_rename_request, on_shutdown, on_signature_help_request, on_test_run_request, on_tests_request, - LspInitializationOptions, }; use serde_json::Value as JsonValue; use thiserror::Error; @@ -80,7 +79,7 @@ mod with_file; mod test_utils; use solver::WrapperSolver; -use types::{notification, request, NargoTest, NargoTestId, Position, Range, Url}; +use types::{NargoTest, NargoTestId, Position, Range, Url, notification, request}; use with_file::parsed_module_with_file; #[derive(Debug, Error)] @@ -239,11 +238,7 @@ fn get_package_tests_in_crate( }) .collect(); - if package_tests.is_empty() { - None - } else { - Some(package_tests) - } + if package_tests.is_empty() { None } else { Some(package_tests) } } fn byte_span_to_range<'a, F: files::Files<'a> + ?Sized>( diff --git a/tooling/lsp/src/notifications/mod.rs b/tooling/lsp/src/notifications/mod.rs index c6b0f110ec3..b7ba8cd4761 100644 --- a/tooling/lsp/src/notifications/mod.rs +++ b/tooling/lsp/src/notifications/mod.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use std::path::PathBuf; use crate::{ - insert_all_files_for_workspace_into_file_manager, PackageCacheData, WorkspaceCacheData, + PackageCacheData, WorkspaceCacheData, insert_all_files_for_workspace_into_file_manager, }; use async_lsp::{ErrorCode, LanguageClient, ResponseError}; use fm::{FileManager, FileMap}; @@ -11,17 +11,17 @@ use fxhash::FxHashMap as HashMap; use lsp_types::{DiagnosticRelatedInformation, DiagnosticTag, Url}; use noirc_driver::check_crate; use noirc_errors::reporter::CustomLabel; -use noirc_errors::{DiagnosticKind, FileDiagnostic, Location}; +use noirc_errors::{CustomDiagnostic, DiagnosticKind, Location}; use crate::types::{ - notification, Diagnostic, DiagnosticSeverity, DidChangeConfigurationParams, - DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, - DidSaveTextDocumentParams, InitializedParams, NargoPackageTests, PublishDiagnosticsParams, + Diagnostic, DiagnosticSeverity, DidChangeConfigurationParams, DidChangeTextDocumentParams, + DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, + InitializedParams, NargoPackageTests, PublishDiagnosticsParams, notification, }; use crate::{ - byte_span_to_range, get_package_tests_in_crate, parse_diff, resolve_workspace_for_source_path, - LspState, + LspState, byte_span_to_range, get_package_tests_in_crate, parse_diff, + resolve_workspace_for_source_path, }; pub(super) fn on_initialized( @@ -191,16 +191,16 @@ fn publish_diagnostics( package_root_dir: &PathBuf, files: &FileMap, fm: &FileManager, - file_diagnostics: Vec, + custom_diagnostics: Vec, ) { let mut diagnostics_per_url: HashMap> = HashMap::default(); - for file_diagnostic in file_diagnostics.into_iter() { - let file_id = file_diagnostic.file_id; - let path = fm.path(file_id).expect("file must exist to have emitted diagnostic"); + for custom_diagnostic in custom_diagnostics.into_iter() { + let file = custom_diagnostic.file; + let path = fm.path(file).expect("file must exist to have emitted diagnostic"); if let Ok(uri) = Url::from_file_path(path) { if let Some(diagnostic) = - file_diagnostic_to_diagnostic(file_diagnostic, files, fm, uri.clone()) + custom_diagnostic_to_diagnostic(custom_diagnostic, files, fm, uri.clone()) { diagnostics_per_url.entry(uri).or_default().push(diagnostic); } @@ -232,21 +232,18 @@ fn publish_diagnostics( state.files_with_errors.insert(package_root_dir.clone(), new_files_with_errors); } -fn file_diagnostic_to_diagnostic( - file_diagnostic: FileDiagnostic, +fn custom_diagnostic_to_diagnostic( + diagnostic: CustomDiagnostic, files: &FileMap, fm: &FileManager, uri: Url, ) -> Option { - let file_id = file_diagnostic.file_id; - let diagnostic = file_diagnostic.diagnostic; - if diagnostic.secondaries.is_empty() { return None; } let span = diagnostic.secondaries.first().unwrap().location.span; - let range = byte_span_to_range(files, file_id, span.into())?; + let range = byte_span_to_range(files, diagnostic.file, span.into())?; let severity = match diagnostic.kind { DiagnosticKind::Error => DiagnosticSeverity::ERROR, diff --git a/tooling/lsp/src/requests/code_action.rs b/tooling/lsp/src/requests/code_action.rs index a75acfe6d50..6d74ce2d1f9 100644 --- a/tooling/lsp/src/requests/code_action.rs +++ b/tooling/lsp/src/requests/code_action.rs @@ -11,6 +11,10 @@ use lsp_types::{ TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit, }; use noirc_errors::Span; +use noirc_frontend::{ + ParsedModule, + parser::{Item, ItemKind, ParsedSubModule}, +}; use noirc_frontend::{ ast::{ CallExpression, ConstructorExpression, ItemVisibility, MethodCallExpression, NoirTraitImpl, @@ -21,14 +25,10 @@ use noirc_frontend::{ node_interner::{NodeInterner, Reexport}, usage_tracker::UsageTracker, }; -use noirc_frontend::{ - parser::{Item, ItemKind, ParsedSubModule}, - ParsedModule, -}; use crate::{ - modules::get_ancestor_module_reexport, use_segment_positions::UseSegmentPositions, utils, - visibility::module_def_id_is_visible, LspState, + LspState, modules::get_ancestor_module_reexport, use_segment_positions::UseSegmentPositions, + utils, visibility::module_def_id_is_visible, }; use super::{process_request, to_lsp_location}; @@ -44,7 +44,7 @@ mod tests; pub(crate) fn on_code_action_request( state: &mut LspState, params: CodeActionParams, -) -> impl Future, ResponseError>> { +) -> impl Future, ResponseError>> + use<> { let uri = params.text_document.clone().uri; let position = params.range.start; let text_document_position_params = diff --git a/tooling/lsp/src/requests/code_action/import_or_qualify.rs b/tooling/lsp/src/requests/code_action/import_or_qualify.rs index 7859b08f5e7..070dcfcde90 100644 --- a/tooling/lsp/src/requests/code_action/import_or_qualify.rs +++ b/tooling/lsp/src/requests/code_action/import_or_qualify.rs @@ -6,7 +6,7 @@ use crate::{ byte_span_to_range, modules::module_def_id_relative_path, use_segment_positions::{ - use_completion_item_additional_text_edits, UseCompletionItemAdditionTextEditsRequest, + UseCompletionItemAdditionTextEditsRequest, use_completion_item_additional_text_edits, }, }; diff --git a/tooling/lsp/src/requests/code_action/import_trait.rs b/tooling/lsp/src/requests/code_action/import_trait.rs index 56976c119cd..379b627f878 100644 --- a/tooling/lsp/src/requests/code_action/import_trait.rs +++ b/tooling/lsp/src/requests/code_action/import_trait.rs @@ -11,7 +11,7 @@ use crate::{ modules::module_def_id_relative_path, requests::TraitReexport, use_segment_positions::{ - use_completion_item_additional_text_edits, UseCompletionItemAdditionTextEditsRequest, + UseCompletionItemAdditionTextEditsRequest, use_completion_item_additional_text_edits, }, }; diff --git a/tooling/lsp/src/requests/code_action/remove_bang_from_call.rs b/tooling/lsp/src/requests/code_action/remove_bang_from_call.rs index 8f6fed76cac..e2ef2ef84ee 100644 --- a/tooling/lsp/src/requests/code_action/remove_bang_from_call.rs +++ b/tooling/lsp/src/requests/code_action/remove_bang_from_call.rs @@ -1,6 +1,6 @@ use lsp_types::TextEdit; use noirc_errors::{Location, Span}; -use noirc_frontend::{node_interner::ReferenceId, QuotedType, Type}; +use noirc_frontend::{QuotedType, Type, node_interner::ReferenceId}; use crate::byte_span_to_range; diff --git a/tooling/lsp/src/requests/code_action/remove_unused_import.rs b/tooling/lsp/src/requests/code_action/remove_unused_import.rs index b9837eca65d..41d43baa656 100644 --- a/tooling/lsp/src/requests/code_action/remove_unused_import.rs +++ b/tooling/lsp/src/requests/code_action/remove_unused_import.rs @@ -4,10 +4,10 @@ use fm::FileId; use lsp_types::TextEdit; use noirc_errors::{Location, Span}; use noirc_frontend::{ + ParsedModule, ast::{Ident, ItemVisibility, UseTree, UseTreeKind}, parser::{Item, ItemKind}, usage_tracker::UnusedItem, - ParsedModule, }; use crate::byte_span_to_range; @@ -81,11 +81,7 @@ fn use_tree_without_unused_import( match &use_tree.kind { UseTreeKind::Path(name, alias) => { let ident = alias.as_ref().unwrap_or(name); - if unused_items.contains_key(ident) { - (None, 1) - } else { - (Some(use_tree.clone()), 0) - } + if unused_items.contains_key(ident) { (None, 1) } else { (Some(use_tree.clone()), 0) } } UseTreeKind::List(use_trees) => { let mut new_use_trees: Vec = Vec::new(); diff --git a/tooling/lsp/src/requests/code_action/tests.rs b/tooling/lsp/src/requests/code_action/tests.rs index f5748e29d97..23026d16d94 100644 --- a/tooling/lsp/src/requests/code_action/tests.rs +++ b/tooling/lsp/src/requests/code_action/tests.rs @@ -56,11 +56,7 @@ pub(crate) async fn assert_code_action(title: &str, src: &str, expected: &str) { .iter() .filter_map(|action| { if let CodeActionOrCommand::CodeAction(action) = action { - if action.title == title { - Some(action) - } else { - None - } + if action.title == title { Some(action) } else { None } } else { None } diff --git a/tooling/lsp/src/requests/code_lens_request.rs b/tooling/lsp/src/requests/code_lens_request.rs index ab98ab8bf10..1870e8e0602 100644 --- a/tooling/lsp/src/requests/code_lens_request.rs +++ b/tooling/lsp/src/requests/code_lens_request.rs @@ -7,9 +7,8 @@ use noirc_driver::check_crate; use noirc_frontend::hir::FunctionNameMatch; use crate::{ - byte_span_to_range, prepare_source, resolve_workspace_for_source_path, + LspState, byte_span_to_range, prepare_source, resolve_workspace_for_source_path, types::{CodeLens, CodeLensParams, CodeLensResult, Command}, - LspState, }; const ARROW: &str = "â–¶\u{fe0e}"; @@ -40,7 +39,7 @@ fn package_selection_args(workspace: &Workspace, package: &Package) -> Vec impl Future> { +) -> impl Future> + use<> { future::ready(on_code_lens_request_inner(state, params)) } diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index 622293b7093..eab8522693f 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -15,6 +15,7 @@ use kinds::{FunctionCompletionKind, FunctionKind, RequestedItems}; use lsp_types::{CompletionItem, CompletionItemKind, CompletionParams, CompletionResponse}; use noirc_errors::{Location, Span}; use noirc_frontend::{ + DataType, Kind, ParsedModule, Type, TypeBinding, ast::{ AsTraitPath, AttributeTarget, BlockExpression, CallExpression, ConstructorExpression, Expression, ExpressionKind, ForLoopStatement, GenericTypeArgs, Ident, IfExpression, @@ -35,17 +36,16 @@ use noirc_frontend::{ node_interner::{FuncId, NodeInterner, ReferenceId, TypeId}, parser::{Item, ItemKind, ParsedSubModule}, token::{MetaAttribute, Token, Tokens}, - DataType, Kind, ParsedModule, Type, TypeBinding, }; use sort_text::underscore_sort_text; use crate::{ - requests::to_lsp_location, trait_impl_method_stub_generator::TraitImplMethodStubGenerator, + LspState, requests::to_lsp_location, + trait_impl_method_stub_generator::TraitImplMethodStubGenerator, use_segment_positions::UseSegmentPositions, utils, visibility::module_def_id_is_visible, - LspState, }; -use super::{process_request, TraitReexport}; +use super::{TraitReexport, process_request}; mod auto_import; mod builtins; @@ -57,7 +57,7 @@ mod tests; pub(crate) fn on_completion_request( state: &mut LspState, params: CompletionParams, -) -> impl Future, ResponseError>> { +) -> impl Future, ResponseError>> + use<> { let uri = params.text_document_position.clone().text_document.uri; let result = process_request(state, params.text_document_position.clone(), |args| { @@ -608,7 +608,7 @@ impl<'a> NodeFinder<'a> { self.complete_tuple_fields(types, self_prefix); } Type::TypeVariable(var) | Type::NamedGeneric(var, _) => { - if let TypeBinding::Bound(ref typ) = &*var.borrow() { + if let TypeBinding::Bound(typ) = &*var.borrow() { return self.complete_type_fields_and_methods( typ, prefix, @@ -1906,13 +1906,10 @@ fn get_field_type(typ: &Type, name: &str) -> Option { } } Type::Alias(alias_type, generics) => Some(alias_type.borrow().get_type(generics)), - Type::TypeVariable(var) | Type::NamedGeneric(var, _) => { - if let TypeBinding::Bound(ref typ) = &*var.borrow() { - get_field_type(typ, name) - } else { - None - } - } + Type::TypeVariable(var) | Type::NamedGeneric(var, _) => match &*var.borrow() { + TypeBinding::Bound(typ) => get_field_type(typ, name), + _ => None, + }, _ => None, } } @@ -1924,13 +1921,10 @@ fn get_array_element_type(typ: Type) -> Option { let typ = alias_type.borrow().get_type(&generics); get_array_element_type(typ) } - Type::TypeVariable(var) | Type::NamedGeneric(var, _) => { - if let TypeBinding::Bound(typ) = &*var.borrow() { - get_array_element_type(typ.clone()) - } else { - None - } - } + Type::TypeVariable(var) | Type::NamedGeneric(var, _) => match &*var.borrow() { + TypeBinding::Bound(typ) => get_array_element_type(typ.clone()), + _ => None, + }, _ => None, } } diff --git a/tooling/lsp/src/requests/completion/auto_import.rs b/tooling/lsp/src/requests/completion/auto_import.rs index acd77a63e48..cc80c8d8e01 100644 --- a/tooling/lsp/src/requests/completion/auto_import.rs +++ b/tooling/lsp/src/requests/completion/auto_import.rs @@ -3,15 +3,15 @@ use noirc_frontend::{ast::ItemVisibility, hir::def_map::ModuleDefId, node_intern use crate::{ modules::{get_ancestor_module_reexport, module_def_id_relative_path}, use_segment_positions::{ - use_completion_item_additional_text_edits, UseCompletionItemAdditionTextEditsRequest, + UseCompletionItemAdditionTextEditsRequest, use_completion_item_additional_text_edits, }, }; use super::{ + NodeFinder, kinds::{FunctionCompletionKind, FunctionKind, RequestedItems}, name_matches, sort_text::auto_import_sort_text, - NodeFinder, }; impl NodeFinder<'_> { diff --git a/tooling/lsp/src/requests/completion/builtins.rs b/tooling/lsp/src/requests/completion/builtins.rs index c8093d50c6a..ce5b5f35f46 100644 --- a/tooling/lsp/src/requests/completion/builtins.rs +++ b/tooling/lsp/src/requests/completion/builtins.rs @@ -3,12 +3,13 @@ use noirc_frontend::{ast::AttributeTarget, token::Keyword}; use strum::IntoEnumIterator; use super::{ + NodeFinder, completion_items::{ completion_item_with_trigger_parameter_hints_command, simple_completion_item, snippet_completion_item, }, kinds::FunctionCompletionKind, - name_matches, NodeFinder, + name_matches, }; impl NodeFinder<'_> { diff --git a/tooling/lsp/src/requests/completion/completion_items.rs b/tooling/lsp/src/requests/completion/completion_items.rs index 394d5e9a46f..bc266c03f76 100644 --- a/tooling/lsp/src/requests/completion/completion_items.rs +++ b/tooling/lsp/src/requests/completion/completion_items.rs @@ -3,26 +3,26 @@ use lsp_types::{ InsertTextFormat, MarkupContent, MarkupKind, }; use noirc_frontend::{ + QuotedType, Type, ast::AttributeTarget, hir::def_map::{ModuleDefId, ModuleId}, hir_def::{function::FuncMeta, stmt::HirPattern}, node_interner::{FuncId, GlobalId, ReferenceId, TraitId, TypeAliasId, TypeId}, - QuotedType, Type, }; use crate::{ modules::{relative_module_full_path, relative_module_id_path}, use_segment_positions::{ - use_completion_item_additional_text_edits, UseCompletionItemAdditionTextEditsRequest, + UseCompletionItemAdditionTextEditsRequest, use_completion_item_additional_text_edits, }, }; use super::{ + FunctionCompletionKind, FunctionKind, NodeFinder, RequestedItems, TraitReexport, sort_text::{ crate_or_module_sort_text, default_sort_text, new_sort_text, operator_sort_text, self_mismatch_sort_text, }, - FunctionCompletionKind, FunctionKind, NodeFinder, RequestedItems, TraitReexport, }; impl NodeFinder<'_> { diff --git a/tooling/lsp/src/requests/completion/kinds.rs b/tooling/lsp/src/requests/completion/kinds.rs index ba6faada6f4..042b10b9cba 100644 --- a/tooling/lsp/src/requests/completion/kinds.rs +++ b/tooling/lsp/src/requests/completion/kinds.rs @@ -1,4 +1,4 @@ -use noirc_frontend::{ast::AttributeTarget, Type}; +use noirc_frontend::{Type, ast::AttributeTarget}; /// When suggest a function as a result of completion, whether to autocomplete its name or its name and parameters. #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/tooling/lsp/src/requests/completion/tests.rs b/tooling/lsp/src/requests/completion/tests.rs index cbe1a93391a..3958b92deb0 100644 --- a/tooling/lsp/src/requests/completion/tests.rs +++ b/tooling/lsp/src/requests/completion/tests.rs @@ -67,11 +67,7 @@ mod completion_tests { .await .expect("Could not execute on_completion_request"); - if let Some(CompletionResponse::Array(items)) = response { - items - } else { - vec![] - } + if let Some(CompletionResponse::Array(items)) = response { items } else { vec![] } } fn assert_items_match(mut items: Vec, mut expected: Vec) { @@ -799,9 +795,11 @@ mod completion_tests { "#; let items = get_completions(src).await; - assert!(items - .iter() - .any(|item| item.label == "true" && item.kind == Some(CompletionItemKind::KEYWORD))); + assert!( + items + .iter() + .any(|item| item.label == "true" && item.kind == Some(CompletionItemKind::KEYWORD)) + ); } #[test] @@ -2659,8 +2657,8 @@ fn main() { } #[test] - async fn test_suggests_only_macro_call_if_comptime_function_returns_quoted_and_outside_comptime( - ) { + async fn test_suggests_only_macro_call_if_comptime_function_returns_quoted_and_outside_comptime() + { let src = r#" comptime fn foobar() -> Quoted {} diff --git a/tooling/lsp/src/requests/document_symbol.rs b/tooling/lsp/src/requests/document_symbol.rs index 3ed4df380b2..4827d8827af 100644 --- a/tooling/lsp/src/requests/document_symbol.rs +++ b/tooling/lsp/src/requests/document_symbol.rs @@ -8,12 +8,12 @@ use lsp_types::{ }; use noirc_errors::Span; use noirc_frontend::{ + ParsedModule, ast::{ Expression, FunctionReturnType, Ident, LetStatement, NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl, TypeImpl, UnresolvedType, UnresolvedTypeData, Visitor, }, parser::ParsedSubModule, - ParsedModule, }; use crate::LspState; @@ -23,7 +23,7 @@ use super::process_request; pub(crate) fn on_document_symbol_request( state: &mut LspState, params: DocumentSymbolParams, -) -> impl Future, ResponseError>> { +) -> impl Future, ResponseError>> + use<> { let Ok(file_path) = params.text_document.uri.to_file_path() else { return future::ready(Ok(None)); }; @@ -660,7 +660,7 @@ mod document_symbol_tests { deprecated: None, range: Range { start: Position { line: 15, character: 7 }, - end: Position { line: 15, character: 24 }, + end: Position { line: 15, character: 25 }, }, selection_range: Range { start: Position { line: 15, character: 7 }, diff --git a/tooling/lsp/src/requests/goto_declaration.rs b/tooling/lsp/src/requests/goto_declaration.rs index bd0f0afb827..9df6a25f8cf 100644 --- a/tooling/lsp/src/requests/goto_declaration.rs +++ b/tooling/lsp/src/requests/goto_declaration.rs @@ -1,7 +1,7 @@ use std::future::{self, Future}; -use crate::types::GotoDeclarationResult; use crate::LspState; +use crate::types::GotoDeclarationResult; use async_lsp::ResponseError; use lsp_types::request::{GotoDeclarationParams, GotoDeclarationResponse}; @@ -11,7 +11,7 @@ use super::{process_request, to_lsp_location}; pub(crate) fn on_goto_declaration_request( state: &mut LspState, params: GotoDeclarationParams, -) -> impl Future> { +) -> impl Future> + use<> { let result = on_goto_definition_inner(state, params); future::ready(result) } diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index a8f4977b056..4e015e94861 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -2,7 +2,7 @@ use std::future::{self, Future}; use crate::attribute_reference_finder::AttributeReferenceFinder; use crate::utils; -use crate::{types::GotoDefinitionResult, LspState}; +use crate::{LspState, types::GotoDefinitionResult}; use async_lsp::ResponseError; use fm::PathString; @@ -14,7 +14,7 @@ use super::{process_request, to_lsp_location}; pub(crate) fn on_goto_definition_request( state: &mut LspState, params: GotoDefinitionParams, -) -> impl Future> { +) -> impl Future> + use<> { let result = on_goto_definition_inner(state, params, false); future::ready(result) } @@ -22,7 +22,7 @@ pub(crate) fn on_goto_definition_request( pub(crate) fn on_goto_type_definition_request( state: &mut LspState, params: GotoTypeDefinitionParams, -) -> impl Future> { +) -> impl Future> + use<> { let result = on_goto_definition_inner(state, params, true); future::ready(result) } diff --git a/tooling/lsp/src/requests/hover.rs b/tooling/lsp/src/requests/hover.rs index cbb7dafd3c5..0b53b56eaf9 100644 --- a/tooling/lsp/src/requests/hover.rs +++ b/tooling/lsp/src/requests/hover.rs @@ -16,7 +16,7 @@ mod from_visitor; pub(crate) fn on_hover_request( state: &mut LspState, params: HoverParams, -) -> impl Future, ResponseError>> { +) -> impl Future, ResponseError>> + use<> { let uri = params.text_document_position_params.text_document.uri.clone(); let position = params.text_document_position_params.position; let result = process_request(state, params.text_document_position_params, |args| { diff --git a/tooling/lsp/src/requests/hover/from_reference.rs b/tooling/lsp/src/requests/hover/from_reference.rs index ab9c6f0e58a..3bc3b3bded7 100644 --- a/tooling/lsp/src/requests/hover/from_reference.rs +++ b/tooling/lsp/src/requests/hover/from_reference.rs @@ -1,6 +1,8 @@ use fm::{FileId, FileMap}; use lsp_types::{Hover, HoverContents, MarkupContent, MarkupKind, Position}; use noirc_frontend::{ + DataType, EnumVariant, Generics, Shared, StructField, Type, TypeAlias, TypeBinding, + TypeVariable, ast::{ItemVisibility, Visibility}, hir::def_map::ModuleId, hir_def::{ @@ -13,14 +15,12 @@ use noirc_frontend::{ DefinitionId, DefinitionKind, ExprId, FuncId, GlobalId, NodeInterner, ReferenceId, TraitId, TraitImplKind, TypeAliasId, TypeId, }, - DataType, EnumVariant, Generics, Shared, StructField, Type, TypeAlias, TypeBinding, - TypeVariable, }; use crate::{ attribute_reference_finder::AttributeReferenceFinder, modules::module_full_path, - requests::{to_lsp_location, ProcessRequestCallbackArgs}, + requests::{ProcessRequestCallbackArgs, to_lsp_location}, utils, }; @@ -338,11 +338,7 @@ fn get_global_array_value( match literal { HirArrayLiteral::Standard(values) => { get_exprs_global_value(interner, &values).map(|value| { - if is_slice { - format!("&[{}]", value) - } else { - format!("[{}]", value) - } + if is_slice { format!("&[{}]", value) } else { format!("[{}]", value) } }) } HirArrayLiteral::Repeated { repeated_element, length } => { @@ -360,11 +356,7 @@ fn get_global_array_value( fn get_exprs_global_value(interner: &NodeInterner, exprs: &[ExprId]) -> Option { let strings: Vec = exprs.iter().filter_map(|value| get_global_value(interner, *value)).collect(); - if strings.len() == exprs.len() { - Some(strings.join(", ")) - } else { - None - } + if strings.len() == exprs.len() { Some(strings.join(", ")) } else { None } } fn format_function(id: FuncId, args: &ProcessRequestCallbackArgs) -> String { @@ -403,11 +395,7 @@ fn format_function(id: FuncId, args: &ProcessRequestCallbackArgs) -> String { .trait_generics .iter() .filter_map(|generic| { - if let Type::NamedGeneric(_, name) = generic { - Some(name) - } else { - None - } + if let Type::NamedGeneric(_, name) = generic { Some(name) } else { None } }) .collect(); diff --git a/tooling/lsp/src/requests/hover/from_visitor.rs b/tooling/lsp/src/requests/hover/from_visitor.rs index 595cd255796..97ead183cd2 100644 --- a/tooling/lsp/src/requests/hover/from_visitor.rs +++ b/tooling/lsp/src/requests/hover/from_visitor.rs @@ -4,12 +4,12 @@ use fm::{FileId, FileMap}; use lsp_types::{Hover, HoverContents, MarkupContent, MarkupKind, Position}; use noirc_errors::{Location, Span}; use noirc_frontend::{ - ast::Visitor, node_interner::NodeInterner, parse_program, signed_field::SignedField, Type, + Type, ast::Visitor, node_interner::NodeInterner, parse_program, signed_field::SignedField, }; use num_bigint::BigInt; use crate::{ - requests::{to_lsp_location, ProcessRequestCallbackArgs}, + requests::{ProcessRequestCallbackArgs, to_lsp_location}, utils, }; @@ -86,9 +86,9 @@ fn format_integer(typ: Type, value: SignedField) -> String { #[cfg(test)] mod tests { use noirc_frontend::{ + Type, ast::{IntegerBitSize, Signedness}, signed_field::SignedField, - Type, }; use super::format_integer; diff --git a/tooling/lsp/src/requests/inlay_hint.rs b/tooling/lsp/src/requests/inlay_hint.rs index c0af56d0340..be7722e744d 100644 --- a/tooling/lsp/src/requests/inlay_hint.rs +++ b/tooling/lsp/src/requests/inlay_hint.rs @@ -8,7 +8,7 @@ use lsp_types::{ }; use noirc_errors::{Location, Span}; use noirc_frontend::{ - self, + self, Kind, Type, TypeBinding, TypeVariable, ast::{ CallExpression, Expression, ExpressionKind, ForLoopStatement, Ident, Lambda, LetStatement, MethodCallExpression, NoirFunction, NoirTraitImpl, Pattern, Statement, TypeImpl, @@ -17,17 +17,16 @@ use noirc_frontend::{ hir_def::stmt::HirPattern, node_interner::{NodeInterner, ReferenceId}, parser::{Item, ParsedSubModule}, - Kind, Type, TypeBinding, TypeVariable, }; -use crate::{utils, LspState}; +use crate::{LspState, utils}; -use super::{process_request, to_lsp_location, InlayHintsOptions}; +use super::{InlayHintsOptions, process_request, to_lsp_location}; pub(crate) fn on_inlay_hint_request( state: &mut LspState, params: InlayHintParams, -) -> impl Future>, ResponseError>> { +) -> impl Future>, ResponseError>> + use<> { let text_document_position_params = TextDocumentPositionParams { text_document: params.text_document.clone(), position: Position { line: 0, character: 0 }, @@ -516,18 +515,17 @@ fn push_type_parts(typ: &Type, parts: &mut Vec, files: &File parts.push(string_part("&mut ")); push_type_parts(typ, parts, files); } - Type::TypeVariable(binding) => { - if let TypeBinding::Unbound(_, kind) = &*binding.borrow() { - match kind { - Kind::Any | Kind::Normal => push_type_variable_parts(binding, parts, files), - Kind::Integer => push_type_parts(&Type::default_int_type(), parts, files), - Kind::IntegerOrField => parts.push(string_part("Field")), - Kind::Numeric(ref typ) => push_type_parts(typ, parts, files), - } - } else { + Type::TypeVariable(binding) => match &*binding.borrow() { + TypeBinding::Unbound(_, kind) => match kind { + Kind::Any | Kind::Normal => push_type_variable_parts(binding, parts, files), + Kind::Integer => push_type_parts(&Type::default_int_type(), parts, files), + Kind::IntegerOrField => parts.push(string_part("Field")), + Kind::Numeric(typ) => push_type_parts(typ, parts, files), + }, + _ => { push_type_variable_parts(binding, parts, files); } - } + }, Type::CheckedCast { to, .. } => push_type_parts(to, parts, files), Type::FieldElement @@ -919,8 +917,8 @@ mod inlay_hints_tests { } #[test] - async fn test_do_not_show_parameter_inlay_hints_if_single_param_name_is_suffix_of_function_name( - ) { + async fn test_do_not_show_parameter_inlay_hints_if_single_param_name_is_suffix_of_function_name() + { let inlay_hints = get_inlay_hints(64, 67, parameter_hints()).await; assert!(inlay_hints.is_empty()); } diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index e5bcc66e767..9126ab38e10 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -2,13 +2,13 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::{collections::HashMap, future::Future}; -use crate::{insert_all_files_for_workspace_into_file_manager, parse_diff, PackageCacheData}; +use crate::{PackageCacheData, insert_all_files_for_workspace_into_file_manager, parse_diff}; use crate::{ resolve_workspace_for_source_path, types::{CodeLensOptions, InitializeParams}, }; use async_lsp::{ErrorCode, ResponseError}; -use fm::{codespan_files::Error, FileMap, PathString}; +use fm::{FileMap, PathString, codespan_files::Error}; use lsp_types::{ CodeActionKind, DeclarationCapability, Location, Position, TextDocumentPositionParams, TextDocumentSyncCapability, TextDocumentSyncKind, TypeDefinitionProviderCapability, Url, @@ -25,8 +25,8 @@ use noirc_frontend::{graph::Dependency, node_interner::NodeInterner}; use serde::{Deserialize, Serialize}; use crate::{ - types::{InitializeResult, NargoCapability, NargoTestsOptions, ServerCapabilities}, LspState, + types::{InitializeResult, NargoCapability, NargoTestsOptions, ServerCapabilities}, }; // Handlers @@ -191,7 +191,7 @@ impl Default for LspInitializationOptions { pub(crate) fn on_initialize( state: &mut LspState, params: InitializeParams, -) -> impl Future> { +) -> impl Future> + use<> { state.root_path = params.root_uri.and_then(|root_uri| root_uri.to_file_path().ok()); let initialization_options: LspInitializationOptions = params .initialization_options @@ -293,7 +293,7 @@ pub(crate) fn on_initialize( pub(crate) fn on_formatting( state: &mut LspState, params: lsp_types::DocumentFormattingParams, -) -> impl Future>, ResponseError>> { +) -> impl Future>, ResponseError>> + use<> { std::future::ready(on_formatting_inner(state, params)) } @@ -441,7 +441,7 @@ where pub(crate) fn on_shutdown( _state: &mut LspState, _params: (), -) -> impl Future> { +) -> impl Future> + use<> { async { Ok(()) } } @@ -628,11 +628,7 @@ pub(crate) fn find_all_references_in_workspace( }); locations.dedup(); - if locations.is_empty() { - None - } else { - Some(locations) - } + if locations.is_empty() { None } else { Some(locations) } } else { None } @@ -671,7 +667,7 @@ mod initialization { }; use tokio::test; - use crate::{requests::on_initialize, types::ServerCapabilities, LspState}; + use crate::{LspState, requests::on_initialize, types::ServerCapabilities}; #[test] async fn test_on_initialize() { diff --git a/tooling/lsp/src/requests/references.rs b/tooling/lsp/src/requests/references.rs index 3b4ef12b5b7..fbe69c99871 100644 --- a/tooling/lsp/src/requests/references.rs +++ b/tooling/lsp/src/requests/references.rs @@ -10,7 +10,7 @@ use super::{find_all_references_in_workspace, process_request}; pub(crate) fn on_references_request( state: &mut LspState, params: ReferenceParams, -) -> impl Future>, ResponseError>> { +) -> impl Future>, ResponseError>> + use<> { let include_declaration = params.context.include_declaration; let result = process_request(state, params.text_document_position, |args| { find_all_references_in_workspace( diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 01181fc60f4..00e39451cae 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -16,7 +16,7 @@ use super::{find_all_references_in_workspace, process_request}; pub(crate) fn on_prepare_rename_request( state: &mut LspState, params: TextDocumentPositionParams, -) -> impl Future, ResponseError>> { +) -> impl Future, ResponseError>> + use<> { let result = process_request(state, params, |args| { let reference_id = args.interner.reference_at_location(args.location); let rename_possible = match reference_id { @@ -33,7 +33,7 @@ pub(crate) fn on_prepare_rename_request( pub(crate) fn on_rename_request( state: &mut LspState, params: RenameParams, -) -> impl Future, ResponseError>> { +) -> impl Future, ResponseError>> + use<> { let result = process_request(state, params.text_document_position, |args| { let rename_changes = find_all_references_in_workspace( args.location, diff --git a/tooling/lsp/src/requests/signature_help.rs b/tooling/lsp/src/requests/signature_help.rs index ac15835ddac..1709106e121 100644 --- a/tooling/lsp/src/requests/signature_help.rs +++ b/tooling/lsp/src/requests/signature_help.rs @@ -7,6 +7,7 @@ use lsp_types::{ }; use noirc_errors::{Location, Span}; use noirc_frontend::{ + ParsedModule, Type, ast::{ CallExpression, ConstrainExpression, ConstrainKind, Expression, FunctionReturnType, MethodCallExpression, Statement, Visitor, @@ -14,10 +15,9 @@ use noirc_frontend::{ hir_def::{function::FuncMeta, stmt::HirPattern}, node_interner::{NodeInterner, ReferenceId}, parser::Item, - ParsedModule, Type, }; -use crate::{utils, LspState}; +use crate::{LspState, utils}; use super::process_request; @@ -26,7 +26,7 @@ mod tests; pub(crate) fn on_signature_help_request( state: &mut LspState, params: SignatureHelpParams, -) -> impl Future, ResponseError>> { +) -> impl Future, ResponseError>> + use<> { let uri = params.text_document_position_params.clone().text_document.uri; let result = process_request(state, params.text_document_position_params.clone(), |args| { diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index e2d8edd46c8..6b7a53e4596 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -3,24 +3,23 @@ use std::future::{self, Future}; use crate::insert_all_files_for_workspace_into_file_manager; use async_lsp::{ErrorCode, ResponseError}; use nargo::{ - foreign_calls::DefaultForeignCallBuilder, - ops::{run_test, TestStatus}, PrintOutput, + foreign_calls::DefaultForeignCallBuilder, + ops::{TestStatus, run_test}, }; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{check_crate, CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; +use nargo_toml::{PackageSelection, find_package_manifest, resolve_workspace_from_toml}; +use noirc_driver::{CompileOptions, NOIR_ARTIFACT_VERSION_STRING, check_crate}; use noirc_frontend::hir::FunctionNameMatch; use crate::{ - parse_diff, + LspState, parse_diff, types::{NargoTestRunParams, NargoTestRunResult}, - LspState, }; pub(crate) fn on_test_run_request( state: &mut LspState, params: NargoTestRunParams, -) -> impl Future> { +) -> impl Future> + use<> { future::ready(on_test_run_request_inner(state, params)) } @@ -120,7 +119,7 @@ fn on_test_run_request_inner( TestStatus::CompileError(diag) => NargoTestRunResult { id: params.id.clone(), result: "error".to_string(), - message: Some(diag.diagnostic.message), + message: Some(diag.message), }, }; Ok(result) diff --git a/tooling/lsp/src/requests/tests.rs b/tooling/lsp/src/requests/tests.rs index 81910bebedb..234bd971eb5 100644 --- a/tooling/lsp/src/requests/tests.rs +++ b/tooling/lsp/src/requests/tests.rs @@ -3,19 +3,18 @@ use std::future::{self, Future}; use crate::insert_all_files_for_workspace_into_file_manager; use async_lsp::{ErrorCode, LanguageClient, ResponseError}; use lsp_types::{LogMessageParams, MessageType}; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{check_crate, NOIR_ARTIFACT_VERSION_STRING}; +use nargo_toml::{PackageSelection, find_package_manifest, resolve_workspace_from_toml}; +use noirc_driver::{NOIR_ARTIFACT_VERSION_STRING, check_crate}; use crate::{ - get_package_tests_in_crate, parse_diff, + LspState, get_package_tests_in_crate, parse_diff, types::{NargoPackageTests, NargoTestsParams, NargoTestsResult}, - LspState, }; pub(crate) fn on_tests_request( state: &mut LspState, params: NargoTestsParams, -) -> impl Future> { +) -> impl Future> + use<> { future::ready(on_tests_request_inner(state, params)) } @@ -73,9 +72,5 @@ fn on_tests_request_inner( }) .collect(); - if package_tests.is_empty() { - Ok(None) - } else { - Ok(Some(package_tests)) - } + if package_tests.is_empty() { Ok(None) } else { Ok(Some(package_tests)) } } diff --git a/tooling/lsp/src/trait_impl_method_stub_generator.rs b/tooling/lsp/src/trait_impl_method_stub_generator.rs index a7444f81993..3a60a882aea 100644 --- a/tooling/lsp/src/trait_impl_method_stub_generator.rs +++ b/tooling/lsp/src/trait_impl_method_stub_generator.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use noirc_frontend::{ + Kind, ResolvedGeneric, Type, ast::{NoirTraitImpl, UnresolvedTypeData}, graph::CrateId, hir::{ @@ -9,7 +10,6 @@ use noirc_frontend::{ }, hir_def::{function::FuncMeta, stmt::HirPattern, traits::Trait}, node_interner::{FunctionModifiers, NodeInterner, ReferenceId}, - Kind, ResolvedGeneric, Type, }; use crate::modules::relative_module_id_path; @@ -447,7 +447,7 @@ impl<'a> TraitImplMethodStubGenerator<'a> { Kind::Any | Kind::Normal | Kind::Integer | Kind::IntegerOrField => { self.string.push_str(&generic.name); } - Kind::Numeric(ref typ) => { + Kind::Numeric(typ) => { self.string.push_str("let "); self.string.push_str(&generic.name); self.string.push_str(": "); diff --git a/tooling/lsp/src/types.rs b/tooling/lsp/src/types.rs index b49377787e8..21d274a3776 100644 --- a/tooling/lsp/src/types.rs +++ b/tooling/lsp/src/types.rs @@ -15,7 +15,7 @@ pub(crate) use lsp_types::{ }; pub(crate) mod request { - use lsp_types::{request::Request, InitializeParams}; + use lsp_types::{InitializeParams, request::Request}; use super::{ InitializeResult, NargoTestRunParams, NargoTestRunResult, NargoTestsParams, diff --git a/tooling/lsp/src/utils.rs b/tooling/lsp/src/utils.rs index 96db1f7bfa2..ca607128bf2 100644 --- a/tooling/lsp/src/utils.rs +++ b/tooling/lsp/src/utils.rs @@ -51,9 +51,5 @@ pub(crate) fn character_to_line_offset(line: &str, character: u32) -> Option, abi: &Abi, debug: &[DebugInfo], -) -> Option { +) -> Option { let source_locations = match nargo_err { NargoError::ExecutionError(execution_error) => { extract_locations_from_error(execution_error, debug)? @@ -242,5 +240,5 @@ pub fn try_to_diagnose_runtime_error( let location = *source_locations.last()?; let message = extract_message_from_error(&abi.error_types, nargo_err); let error = CustomDiagnostic::simple_error(message, String::new(), location); - Some(error.with_call_stack(source_locations).in_file(location.file)) + Some(error.with_call_stack(source_locations)) } diff --git a/tooling/nargo/src/foreign_calls/default.rs b/tooling/nargo/src/foreign_calls/default.rs index 753c9b8b475..c6053a1175e 100644 --- a/tooling/nargo/src/foreign_calls/default.rs +++ b/tooling/nargo/src/foreign_calls/default.rs @@ -4,10 +4,10 @@ use serde::{Deserialize, Serialize}; use crate::PrintOutput; use super::{ + ForeignCallExecutor, layers::{self, Either, Layer, Layering}, mocker::{DisabledMockForeignCallExecutor, MockForeignCallExecutor}, print::PrintForeignCallExecutor, - ForeignCallExecutor, }; #[cfg(feature = "rpc")] @@ -80,7 +80,7 @@ impl<'a> DefaultForeignCallBuilder<'a> { use rand::Rng; base.add_layer(self.resolver_url.map(|resolver_url| { - let id = rand::thread_rng().gen(); + let id = rand::thread_rng().r#gen(); RPCForeignCallExecutor::new( &resolver_url, id, @@ -136,7 +136,7 @@ impl DefaultForeignCallExecutor { resolver_url: Option<&str>, root_path: Option, package_name: Option, - ) -> impl ForeignCallExecutor + 'a + ) -> impl ForeignCallExecutor + 'a + use<'a, F> where F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, { diff --git a/tooling/nargo/src/foreign_calls/layers.rs b/tooling/nargo/src/foreign_calls/layers.rs index 83145cacb44..4b1d17bdf65 100644 --- a/tooling/nargo/src/foreign_calls/layers.rs +++ b/tooling/nargo/src/foreign_calls/layers.rs @@ -1,4 +1,4 @@ -use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; +use acvm::{AcirField, acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo}; use super::{ForeignCallError, ForeignCallExecutor}; diff --git a/tooling/nargo/src/foreign_calls/mocker.rs b/tooling/nargo/src/foreign_calls/mocker.rs index 41fac610052..3d432b18ff9 100644 --- a/tooling/nargo/src/foreign_calls/mocker.rs +++ b/tooling/nargo/src/foreign_calls/mocker.rs @@ -1,7 +1,7 @@ use acvm::{ + AcirField, acir::brillig::{ForeignCallParam, ForeignCallResult}, pwg::ForeignCallWaitInfo, - AcirField, }; use noirc_abi::decode_string_value; diff --git a/tooling/nargo/src/foreign_calls/print.rs b/tooling/nargo/src/foreign_calls/print.rs index fb5621da942..a225fe31dcb 100644 --- a/tooling/nargo/src/foreign_calls/print.rs +++ b/tooling/nargo/src/foreign_calls/print.rs @@ -1,7 +1,7 @@ use acvm::{ + AcirField, acir::brillig::{ForeignCallParam, ForeignCallResult}, pwg::ForeignCallWaitInfo, - AcirField, }; use noirc_abi::{decode_printable_value, decode_string_value}; use noirc_printable_type::{PrintableType, PrintableValueDisplay}; diff --git a/tooling/nargo/src/foreign_calls/rpc.rs b/tooling/nargo/src/foreign_calls/rpc.rs index 89a748b6c45..6e485812885 100644 --- a/tooling/nargo/src/foreign_calls/rpc.rs +++ b/tooling/nargo/src/foreign_calls/rpc.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; +use acvm::{AcirField, acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo}; use jsonrpsee::{ core::client::ClientT, http_client::{HttpClient, HttpClientBuilder}, @@ -115,8 +115,8 @@ where #[cfg(test)] mod tests { use acvm::{ - acir::brillig::ForeignCallParam, brillig_vm::brillig::ForeignCallResult, - pwg::ForeignCallWaitInfo, FieldElement, + FieldElement, acir::brillig::ForeignCallParam, brillig_vm::brillig::ForeignCallResult, + pwg::ForeignCallWaitInfo, }; use jsonrpsee::proc_macros::rpc; use jsonrpsee::server::Server; diff --git a/tooling/nargo/src/lib.rs b/tooling/nargo/src/lib.rs index f046f2d38d0..11615b3de72 100644 --- a/tooling/nargo/src/lib.rs +++ b/tooling/nargo/src/lib.rs @@ -22,11 +22,11 @@ use std::{ path::PathBuf, }; -use fm::{FileManager, FILE_EXTENSION}; +use fm::{FILE_EXTENSION, FileManager}; use noirc_driver::{add_dep, prepare_crate, prepare_dependency}; use noirc_frontend::{ graph::{CrateId, CrateName}, - hir::{def_map::parse_file, Context, ParsedFiles}, + hir::{Context, ParsedFiles, def_map::parse_file}, }; use package::{Dependency, Package}; use rayon::prelude::*; diff --git a/tooling/nargo/src/ops/check.rs b/tooling/nargo/src/ops/check.rs index f22def8bd91..129aa1bd788 100644 --- a/tooling/nargo/src/ops/check.rs +++ b/tooling/nargo/src/ops/check.rs @@ -1,6 +1,6 @@ use acvm::compiler::CircuitSimulator; use noirc_driver::{CompiledProgram, ErrorsAndWarnings}; -use noirc_errors::{CustomDiagnostic, FileDiagnostic}; +use noirc_errors::CustomDiagnostic; /// Run each function through a circuit simulator to check that they are solvable. #[tracing::instrument(level = "trace", skip_all)] @@ -8,13 +8,10 @@ pub fn check_program(compiled_program: &CompiledProgram) -> Result<(), ErrorsAnd for (i, circuit) in compiled_program.program.functions.iter().enumerate() { let mut simulator = CircuitSimulator::default(); if !simulator.check_circuit(circuit) { - let diag = FileDiagnostic { - file_id: fm::FileId::dummy(), - diagnostic: CustomDiagnostic::from_message(&format!( - "Circuit \"{}\" is not solvable", - compiled_program.names[i] - )), - }; + let diag = CustomDiagnostic::from_message( + &format!("Circuit \"{}\" is not solvable", compiled_program.names[i]), + fm::FileId::dummy(), + ); return Err(vec![diag]); } } diff --git a/tooling/nargo/src/ops/compile.rs b/tooling/nargo/src/ops/compile.rs index 8c44bf35243..7a3ddbfe3bc 100644 --- a/tooling/nargo/src/ops/compile.rs +++ b/tooling/nargo/src/ops/compile.rs @@ -1,6 +1,6 @@ use fm::FileManager; use noirc_driver::{ - link_to_debug_crate, CompilationResult, CompileOptions, CompiledContract, CompiledProgram, + CompilationResult, CompileOptions, CompiledContract, CompiledProgram, link_to_debug_crate, }; use noirc_frontend::debug::DebugInstrumenter; use noirc_frontend::hir::ParsedFiles; @@ -120,11 +120,7 @@ pub fn collect_errors(results: Vec>) -> CompilationResul } } - if errors.is_empty() { - Ok((artifacts, warnings)) - } else { - Err(errors) - } + if errors.is_empty() { Ok((artifacts, warnings)) } else { Err(errors) } } pub fn report_errors( diff --git a/tooling/nargo/src/ops/execute.rs b/tooling/nargo/src/ops/execute.rs index 57116ec2efd..699c54e3f52 100644 --- a/tooling/nargo/src/ops/execute.rs +++ b/tooling/nargo/src/ops/execute.rs @@ -4,14 +4,14 @@ use acvm::acir::circuit::{ }; use acvm::acir::native_types::WitnessStack; use acvm::pwg::{ - ACVMStatus, ErrorLocation, OpcodeNotSolvable, OpcodeResolutionError, ProfilingSamples, ACVM, + ACVM, ACVMStatus, ErrorLocation, OpcodeNotSolvable, OpcodeResolutionError, ProfilingSamples, }; -use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; use acvm::{AcirField, BlackBoxFunctionSolver}; +use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; +use crate::NargoError; use crate::errors::ExecutionError; use crate::foreign_calls::ForeignCallExecutor; -use crate::NargoError; struct ProgramExecutor<'a, F, B: BlackBoxFunctionSolver, E: ForeignCallExecutor> { functions: &'a [Circuit], diff --git a/tooling/nargo/src/ops/mod.rs b/tooling/nargo/src/ops/mod.rs index 7a52a829be3..7ce34b1acd2 100644 --- a/tooling/nargo/src/ops/mod.rs +++ b/tooling/nargo/src/ops/mod.rs @@ -7,7 +7,7 @@ pub use self::optimize::{optimize_contract, optimize_program}; pub use self::transform::{transform_contract, transform_program}; pub use self::execute::{execute_program, execute_program_with_profiling}; -pub use self::test::{run_test, TestStatus}; +pub use self::test::{TestStatus, run_test}; mod check; mod compile; diff --git a/tooling/nargo/src/ops/optimize.rs b/tooling/nargo/src/ops/optimize.rs index 07adfb57df4..906309e36f8 100644 --- a/tooling/nargo/src/ops/optimize.rs +++ b/tooling/nargo/src/ops/optimize.rs @@ -1,4 +1,4 @@ -use acvm::{acir::circuit::Program, FieldElement}; +use acvm::{FieldElement, acir::circuit::Program}; use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; use noirc_errors::debug_info::DebugInfo; diff --git a/tooling/nargo/src/ops/test.rs b/tooling/nargo/src/ops/test.rs index a2f94cd61eb..4f0e63564e2 100644 --- a/tooling/nargo/src/ops/test.rs +++ b/tooling/nargo/src/ops/test.rs @@ -1,20 +1,20 @@ use acvm::{ + AcirField, BlackBoxFunctionSolver, FieldElement, acir::{ brillig::ForeignCallResult, native_types::{WitnessMap, WitnessStack}, }, pwg::ForeignCallWaitInfo, - AcirField, BlackBoxFunctionSolver, FieldElement, }; use noirc_abi::Abi; -use noirc_driver::{compile_no_check, CompileError, CompileOptions, DEFAULT_EXPRESSION_WIDTH}; -use noirc_errors::{debug_info::DebugInfo, FileDiagnostic}; -use noirc_frontend::hir::{def_map::TestFunction, Context}; +use noirc_driver::{CompileError, CompileOptions, DEFAULT_EXPRESSION_WIDTH, compile_no_check}; +use noirc_errors::{CustomDiagnostic, debug_info::DebugInfo}; +use noirc_frontend::hir::{Context, def_map::TestFunction}; use crate::{ - errors::try_to_diagnose_runtime_error, - foreign_calls::{layers, print::PrintOutput, ForeignCallError, ForeignCallExecutor}, NargoError, + errors::try_to_diagnose_runtime_error, + foreign_calls::{ForeignCallError, ForeignCallExecutor, layers, print::PrintOutput}, }; use super::execute_program; @@ -22,9 +22,9 @@ use super::execute_program; #[derive(Debug)] pub enum TestStatus { Pass, - Fail { message: String, error_diagnostic: Option }, + Fail { message: String, error_diagnostic: Option }, Skipped, - CompileError(FileDiagnostic), + CompileError(CustomDiagnostic), } impl TestStatus { @@ -218,7 +218,7 @@ fn test_status_program_compile_pass( fn check_expected_failure_message( test_function: &TestFunction, failed_assertion: Option, - error_diagnostic: Option, + error_diagnostic: Option, ) -> TestStatus { // Extract the expected failure message, if there was one // @@ -235,9 +235,7 @@ fn check_expected_failure_message( // expected_failure_message let expected_failure_message_matches = failed_assertion .as_ref() - .or_else(|| { - error_diagnostic.as_ref().map(|file_diagnostic| &file_diagnostic.diagnostic.message) - }) + .or_else(|| error_diagnostic.as_ref().map(|file_diagnostic| &file_diagnostic.message)) .map(|message| message.contains(expected_failure_message)) .unwrap_or(false); if expected_failure_message_matches { diff --git a/tooling/nargo/src/ops/transform.rs b/tooling/nargo/src/ops/transform.rs index fdda368d150..14aa7459117 100644 --- a/tooling/nargo/src/ops/transform.rs +++ b/tooling/nargo/src/ops/transform.rs @@ -1,6 +1,6 @@ use acvm::{ - acir::circuit::{ExpressionWidth, Program}, FieldElement, + acir::circuit::{ExpressionWidth, Program}, }; use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; diff --git a/tooling/nargo/src/workspace.rs b/tooling/nargo/src/workspace.rs index 2a6669aabdc..f7edc5057f6 100644 --- a/tooling/nargo/src/workspace.rs +++ b/tooling/nargo/src/workspace.rs @@ -4,7 +4,7 @@ // - library will be default use std::{ - iter::{once, Once}, + iter::{Once, once}, path::PathBuf, slice, }; diff --git a/tooling/nargo_cli/benches/criterion.rs b/tooling/nargo_cli/benches/criterion.rs index 0bfb1affc5a..22c1107c71c 100644 --- a/tooling/nargo_cli/benches/criterion.rs +++ b/tooling/nargo_cli/benches/criterion.rs @@ -1,7 +1,7 @@ //! Select representative tests to bench with criterion -use acvm::{acir::native_types::WitnessMap, FieldElement}; +use acvm::{FieldElement, acir::native_types::WitnessMap}; use assert_cmd::prelude::{CommandCargoExt, OutputAssertExt}; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use noir_artifact_cli::fs::{artifact::read_program_from_file, inputs::read_inputs_from_file}; use noirc_driver::CompiledProgram; diff --git a/tooling/nargo_cli/benches/iai.rs b/tooling/nargo_cli/benches/iai.rs index bcd60111ccf..c0526e9a7e2 100644 --- a/tooling/nargo_cli/benches/iai.rs +++ b/tooling/nargo_cli/benches/iai.rs @@ -6,7 +6,7 @@ use std::process::Command; include!("./utils.rs"); macro_rules! iai_command { - ($command_name:tt, $command_string:expr) => { + ($command_name:tt, $command_string:expr_2021) => { paste! { fn []() { let test_program_dirs = get_selected_tests(); diff --git a/tooling/nargo_cli/build.rs b/tooling/nargo_cli/build.rs index 904e404d7c5..b9faf018dfd 100644 --- a/tooling/nargo_cli/build.rs +++ b/tooling/nargo_cli/build.rs @@ -438,7 +438,6 @@ fn generate_compile_success_no_bug_tests(test_file: &mut File, test_data_dir: &P &test_dir, "compile", r#" - nargo.arg("--enable-brillig-constraints-check"); nargo.assert().success().stderr(predicate::str::contains("bug:").not()); "#, &MatrixConfig::default(), @@ -468,7 +467,6 @@ fn generate_compile_success_with_bug_tests(test_file: &mut File, test_data_dir: &test_dir, "compile", r#" - nargo.arg("--enable-brillig-constraints-check"); nargo.assert().success().stderr(predicate::str::contains("bug:")); "#, &MatrixConfig::default(), diff --git a/tooling/nargo_cli/src/cli/check_cmd.rs b/tooling/nargo_cli/src/cli/check_cmd.rs index 4d2d7f97dd9..2247f40f181 100644 --- a/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/tooling/nargo_cli/src/cli/check_cmd.rs @@ -10,7 +10,7 @@ use nargo::{ use nargo_toml::PackageSelection; use noir_artifact_cli::fs::artifact::write_to_file; use noirc_abi::{AbiParameter, AbiType, MAIN_RETURN_NAME}; -use noirc_driver::{check_crate, compute_function_abi, CompileOptions, CrateId}; +use noirc_driver::{CompileOptions, CrateId, check_crate, compute_function_abi}; use noirc_frontend::{ hir::{Context, ParsedFiles}, monomorphization::monomorphize, diff --git a/tooling/nargo_cli/src/cli/compile_cmd.rs b/tooling/nargo_cli/src/cli/compile_cmd.rs index a481277135f..2ee19f5edc0 100644 --- a/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -348,7 +348,7 @@ mod tests { fn read_test_program_dirs( test_programs_dir: &Path, test_sub_dir: &str, - ) -> impl Iterator { + ) -> impl Iterator + use<> { let test_case_dir = test_programs_dir.join(test_sub_dir); std::fs::read_dir(test_case_dir) .unwrap() diff --git a/tooling/nargo_cli/src/cli/dap_cmd.rs b/tooling/nargo_cli/src/cli/dap_cmd.rs index eb2d0ddd1b4..8987ed80d3e 100644 --- a/tooling/nargo_cli/src/cli/dap_cmd.rs +++ b/tooling/nargo_cli/src/cli/dap_cmd.rs @@ -1,11 +1,11 @@ +use acvm::FieldElement; use acvm::acir::circuit::ExpressionWidth; use acvm::acir::native_types::WitnessMap; -use acvm::FieldElement; use bn254_blackbox_solver::Bn254BlackBoxSolver; use clap::Args; use nargo::constants::PROVER_INPUT_FILE; use nargo::workspace::Workspace; -use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; +use nargo_toml::{PackageSelection, get_package_manifest, resolve_workspace_from_toml}; use noir_artifact_cli::fs::inputs::read_inputs_from_file; use noirc_driver::{CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING}; use noirc_frontend::graph::CrateName; @@ -161,7 +161,7 @@ fn loop_uninitialized_dap( server.respond(req.error("Missing launch arguments"))?; continue; }; - let Some(Value::String(ref project_folder)) = additional_data.get("projectFolder") + let Some(Value::String(project_folder)) = additional_data.get("projectFolder") else { server.respond(req.error("Missing project folder argument"))?; continue; diff --git a/tooling/nargo_cli/src/cli/debug_cmd.rs b/tooling/nargo_cli/src/cli/debug_cmd.rs index 1cf7be08486..f9303180fc0 100644 --- a/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -1,7 +1,7 @@ use std::path::Path; -use acvm::acir::native_types::WitnessStack; use acvm::FieldElement; +use acvm::acir::native_types::WitnessStack; use bn254_blackbox_solver::Bn254BlackBoxSolver; use clap::Args; @@ -15,9 +15,9 @@ use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::PackageSelection; use noir_artifact_cli::fs::inputs::read_inputs_from_file; use noir_artifact_cli::fs::witness::save_witness_to_dir; -use noirc_abi::input_parser::InputValue; use noirc_abi::InputMap; -use noirc_driver::{file_manager_with_stdlib, CompileOptions, CompiledProgram}; +use noirc_abi::input_parser::InputValue; +use noirc_driver::{CompileOptions, CompiledProgram, file_manager_with_stdlib}; use noirc_frontend::debug::DebugInstrumenter; use noirc_frontend::hir::ParsedFiles; @@ -215,7 +215,7 @@ fn run_async( if let Some(witness_name) = witness_name { let witness_path = - save_witness_to_dir(solved_witness_stack, witness_name, target_dir)?; + save_witness_to_dir(&solved_witness_stack, witness_name, target_dir)?; println!("[{}] Witness saved to {}", package.name, witness_path.display()); } diff --git a/tooling/nargo_cli/src/cli/execute_cmd.rs b/tooling/nargo_cli/src/cli/execute_cmd.rs index 30848048df9..07a7c1195af 100644 --- a/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -1,24 +1,9 @@ -use std::path::PathBuf; - -use acvm::acir::native_types::WitnessStack; -use acvm::FieldElement; -use bn254_blackbox_solver::Bn254BlackBoxSolver; use clap::Args; use nargo::constants::PROVER_INPUT_FILE; -use nargo::errors::try_to_diagnose_runtime_error; -use nargo::foreign_calls::DefaultForeignCallBuilder; -use nargo::package::Package; use nargo::workspace::Workspace; -use nargo::PrintOutput; use nargo_toml::PackageSelection; -use noir_artifact_cli::fs::artifact::read_program_from_file; -use noir_artifact_cli::fs::inputs::read_inputs_from_file; -use noir_artifact_cli::fs::witness::save_witness_to_dir; -use noirc_abi::input_parser::InputValue; -use noirc_abi::InputMap; -use noirc_artifacts::debug::DebugArtifact; -use noirc_driver::{CompileOptions, CompiledProgram}; +use noirc_driver::CompileOptions; use super::compile_cmd::compile_workspace_full; use super::{LockType, PackageOptions, WorkspaceCommand}; @@ -60,127 +45,27 @@ impl WorkspaceCommand for ExecuteCommand { } pub(crate) fn run(args: ExecuteCommand, workspace: Workspace) -> Result<(), CliError> { - let target_dir = &workspace.target_directory_path(); - // Compile the full workspace in order to generate any build artifacts. compile_workspace_full(&workspace, &args.compile_options)?; let binary_packages = workspace.into_iter().filter(|package| package.is_binary()); for package in binary_packages { let program_artifact_path = workspace.package_build_path(package); - let program: CompiledProgram = read_program_from_file(&program_artifact_path)?.into(); - let abi = program.abi.clone(); - - let results = execute_program_and_decode( - program, - package, - &args.prover_name, - args.oracle_resolver.as_deref(), - Some(workspace.root_dir.clone()), - Some(package.name.to_string()), - args.compile_options.pedantic_solving, - )?; - - println!("[{}] Circuit witness successfully solved", package.name); - if let Some(ref return_value) = results.actual_return { - println!("[{}] Circuit output: {return_value:?}", package.name); - } - - let package_name = package.name.clone().into(); - let witness_name = args.witness_name.as_ref().unwrap_or(&package_name); - let witness_path = save_witness_to_dir(results.witness_stack, witness_name, target_dir)?; - println!("[{}] Witness saved to {}", package.name, witness_path.display()); - - // Sanity checks on the return value after the witness has been saved, so it can be inspected if necessary. - if let Some(expected) = results.expected_return { - if results.actual_return.as_ref() != Some(&expected) { - return Err(CliError::UnexpectedReturn { expected, actual: results.actual_return }); - } - } - // We can expect that if the circuit returns something, it should be non-empty after execution. - if let Some(ref expected) = abi.return_type { - if results.actual_return.is_none() { - return Err(CliError::MissingReturn { expected: expected.clone() }); - } - } + let prover_file = package.root_dir.join(&args.prover_name).with_extension("toml"); + + let cmd = noir_artifact_cli::commands::execute_cmd::ExecuteCommand { + artifact_path: program_artifact_path, + prover_file, + output_dir: Some(workspace.target_directory_path()), + witness_name: Some( + args.witness_name.clone().unwrap_or_else(|| package.name.to_string()), + ), + contract_fn: None, + oracle_resolver: args.oracle_resolver.clone(), + pedantic_solving: args.compile_options.pedantic_solving, + }; + + noir_artifact_cli::commands::execute_cmd::run(cmd)?; } Ok(()) } - -fn execute_program_and_decode( - program: CompiledProgram, - package: &Package, - prover_name: &str, - foreign_call_resolver_url: Option<&str>, - root_path: Option, - package_name: Option, - pedantic_solving: bool, -) -> Result { - // Parse the initial witness values from Prover.toml - let (inputs_map, expected_return) = read_inputs_from_file( - &package.root_dir.join(prover_name).with_extension("toml"), - &program.abi, - )?; - let witness_stack = execute_program( - &program, - &inputs_map, - foreign_call_resolver_url, - root_path, - package_name, - pedantic_solving, - )?; - // Get the entry point witness for the ABI - let main_witness = - &witness_stack.peek().expect("Should have at least one witness on the stack").witness; - let (_, actual_return) = program.abi.decode(main_witness)?; - - Ok(ExecutionResults { expected_return, actual_return, witness_stack }) -} - -struct ExecutionResults { - expected_return: Option, - actual_return: Option, - witness_stack: WitnessStack, -} - -pub(crate) fn execute_program( - compiled_program: &CompiledProgram, - inputs_map: &InputMap, - foreign_call_resolver_url: Option<&str>, - root_path: Option, - package_name: Option, - pedantic_solving: bool, -) -> Result, CliError> { - let initial_witness = compiled_program.abi.encode(inputs_map, None)?; - - let solved_witness_stack_err = nargo::ops::execute_program( - &compiled_program.program, - initial_witness, - &Bn254BlackBoxSolver(pedantic_solving), - &mut DefaultForeignCallBuilder { - output: PrintOutput::Stdout, - enable_mocks: false, - resolver_url: foreign_call_resolver_url.map(|s| s.to_string()), - root_path, - package_name, - } - .build(), - ); - match solved_witness_stack_err { - Ok(solved_witness_stack) => Ok(solved_witness_stack), - Err(err) => { - let debug_artifact = DebugArtifact { - debug_symbols: compiled_program.debug.clone(), - file_map: compiled_program.file_map.clone(), - }; - - if let Some(diagnostic) = - try_to_diagnose_runtime_error(&err, &compiled_program.abi, &compiled_program.debug) - { - diagnostic.report(&debug_artifact, false); - } - - Err(CliError::NargoError(err)) - } - } -} diff --git a/tooling/nargo_cli/src/cli/export_cmd.rs b/tooling/nargo_cli/src/cli/export_cmd.rs index edf57401e90..373dfce86a9 100644 --- a/tooling/nargo_cli/src/cli/export_cmd.rs +++ b/tooling/nargo_cli/src/cli/export_cmd.rs @@ -1,7 +1,7 @@ use nargo::errors::CompileError; use nargo::ops::report_errors; use noir_artifact_cli::fs::artifact::save_program_to_file; -use noirc_errors::FileDiagnostic; +use noirc_errors::CustomDiagnostic; use noirc_frontend::hir::ParsedFiles; use rayon::prelude::*; @@ -12,7 +12,7 @@ use nargo::prepare_package; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::PackageSelection; -use noirc_driver::{compile_no_check, CompileOptions, CompiledProgram}; +use noirc_driver::{CompileOptions, CompiledProgram, compile_no_check}; use clap::Args; @@ -82,7 +82,7 @@ fn compile_exported_functions( |(function_name, function_id)| -> Result<(String, CompiledProgram), CompileError> { // TODO: We should to refactor how to deal with compilation errors to avoid this. let program = compile_no_check(&mut context, compile_options, function_id, None, false) - .map_err(|error| vec![FileDiagnostic::from(error)]); + .map_err(|error| vec![CustomDiagnostic::from(error)]); let program = report_errors( program.map(|program| (program, Vec::new())), diff --git a/tooling/nargo_cli/src/cli/fmt_cmd.rs b/tooling/nargo_cli/src/cli/fmt_cmd.rs index b16ce9d1f7d..53551c13950 100644 --- a/tooling/nargo_cli/src/cli/fmt_cmd.rs +++ b/tooling/nargo_cli/src/cli/fmt_cmd.rs @@ -56,11 +56,8 @@ pub(crate) fn run(args: FormatCommand, workspace: Workspace) -> Result<(), CliEr let is_all_warnings = errors.iter().all(ParserError::is_warning); if !is_all_warnings { let errors = errors - .into_iter() - .map(|error| { - let error = CustomDiagnostic::from(&error); - error.in_file(file_id) - }) + .iter() + .map(CustomDiagnostic::from) .collect(); let _ = report_errors::<()>( diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index 4b397be6c6e..c8a9c289fc0 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -10,18 +10,18 @@ use nargo_toml::PackageSelection; use noir_artifact_cli::fs::{artifact::read_program_from_file, inputs::read_inputs_from_file}; use noirc_artifacts::program::ProgramArtifact; use noirc_artifacts_info::{ - count_opcodes_and_gates_in_program, show_info_report, FunctionInfo, InfoReport, ProgramInfo, + FunctionInfo, InfoReport, ProgramInfo, count_opcodes_and_gates_in_program, show_info_report, }; use noirc_driver::CompileOptions; -use prettytable::{row, Row}; +use prettytable::{Row, row}; use rayon::prelude::*; use serde::Serialize; use crate::errors::CliError; use super::{ - compile_cmd::{compile_workspace_full, get_target_width}, LockType, PackageOptions, WorkspaceCommand, + compile_cmd::{compile_workspace_full, get_target_width}, }; /// Provides detailed information on each of a program's function (represented by a single circuit) diff --git a/tooling/nargo_cli/src/cli/mod.rs b/tooling/nargo_cli/src/cli/mod.rs index 6b823828a58..0c644ae554c 100644 --- a/tooling/nargo_cli/src/cli/mod.rs +++ b/tooling/nargo_cli/src/cli/mod.rs @@ -2,7 +2,7 @@ use clap::{Args, Parser, Subcommand}; use const_format::formatcp; use nargo::workspace::Workspace; use nargo_toml::{ - get_package_manifest, resolve_workspace_from_toml, ManifestError, PackageSelection, + ManifestError, PackageSelection, get_package_manifest, resolve_workspace_from_toml, }; use noirc_driver::{CrateName, NOIR_ARTIFACT_VERSION_STRING}; use std::{ @@ -211,7 +211,10 @@ where /// Lock the (selected) packages in the workspace. /// The lock taken can be shared for commands that only read the artifacts, /// or exclusive for the ones that (might) write artifacts as well. -fn lock_workspace(workspace: &Workspace, exclusive: bool) -> Result, CliError> { +fn lock_workspace( + workspace: &Workspace, + exclusive: bool, +) -> Result>, CliError> { struct LockedFile(File); impl Drop for LockedFile { @@ -269,9 +272,9 @@ mod tests { let err = res.expect_err("should fail because of invalid width"); assert!(err.to_string().contains("expression-width")); - assert!(err - .to_string() - .contains(acvm::compiler::MIN_EXPRESSION_WIDTH.to_string().as_str())); + assert!( + err.to_string().contains(acvm::compiler::MIN_EXPRESSION_WIDTH.to_string().as_str()) + ); } #[test] diff --git a/tooling/nargo_cli/src/cli/new_cmd.rs b/tooling/nargo_cli/src/cli/new_cmd.rs index db9257b8aa0..0777ee2d20a 100644 --- a/tooling/nargo_cli/src/cli/new_cmd.rs +++ b/tooling/nargo_cli/src/cli/new_cmd.rs @@ -1,6 +1,6 @@ use crate::errors::CliError; -use super::{init_cmd::initialize_project, NargoConfig}; +use super::{NargoConfig, init_cmd::initialize_project}; use clap::Args; use nargo::package::{CrateName, PackageType}; use std::path::PathBuf; diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index 85be780f8f5..13c6efe2aee 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -1,9 +1,9 @@ use std::{ collections::{BTreeMap, HashMap}, fmt::Display, - panic::{catch_unwind, UnwindSafe}, + panic::{UnwindSafe, catch_unwind}, path::PathBuf, - sync::{mpsc, Mutex}, + sync::{Mutex, mpsc}, thread, time::Duration, }; @@ -14,12 +14,12 @@ use clap::Args; use fm::FileManager; use formatters::{Formatter, JsonFormatter, PrettyFormatter, TerseFormatter}; use nargo::{ - foreign_calls::DefaultForeignCallBuilder, insert_all_files_for_workspace_into_file_manager, - ops::TestStatus, package::Package, parse_all, prepare_package, workspace::Workspace, - PrintOutput, + PrintOutput, foreign_calls::DefaultForeignCallBuilder, + insert_all_files_for_workspace_into_file_manager, ops::TestStatus, package::Package, parse_all, + prepare_package, workspace::Workspace, }; use nargo_toml::PackageSelection; -use noirc_driver::{check_crate, CompileOptions}; +use noirc_driver::{CompileOptions, check_crate}; use noirc_frontend::hir::{FunctionNameMatch, ParsedFiles}; use crate::{cli::check_cmd::check_crate_and_report_errors, errors::CliError}; @@ -229,11 +229,7 @@ impl<'a> TestRunner<'a> { }; } - if all_passed { - Ok(()) - } else { - Err(CliError::Generic(String::new())) - } + if all_passed { Ok(()) } else { Err(CliError::Generic(String::new())) } } /// Runs all tests. Returns `true` if all tests passed, `false` otherwise. @@ -444,11 +440,7 @@ impl<'a> TestRunner<'a> { } }); - if let Some(error) = error { - Err(error) - } else { - Ok(package_tests) - } + if let Some(error) = error { Err(error) } else { Ok(package_tests) } } /// Compiles a single package and returns all of its tests diff --git a/tooling/nargo_cli/src/cli/test_cmd/formatters.rs b/tooling/nargo_cli/src/cli/test_cmd/formatters.rs index 91d6f0066b1..68628129245 100644 --- a/tooling/nargo_cli/src/cli/test_cmd/formatters.rs +++ b/tooling/nargo_cli/src/cli/test_cmd/formatters.rs @@ -2,8 +2,8 @@ use std::{io::Write, panic::RefUnwindSafe, time::Duration}; use fm::FileManager; use nargo::ops::TestStatus; -use noirc_errors::{reporter::stack_trace, FileDiagnostic}; -use serde_json::{json, Map}; +use noirc_errors::{CustomDiagnostic, reporter::stack_trace}; +use serde_json::{Map, json}; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, StandardStreamLock, WriteColor}; use super::TestResult; @@ -438,7 +438,7 @@ impl Formatter for JsonFormatter { stdout.push_str(message.trim()); if let Some(diagnostic) = error_diagnostic { - if !(diagnostic.diagnostic.is_warning() && silence_warnings) { + if !(diagnostic.is_warning() && silence_warnings) { stdout.push('\n'); stdout.push_str(&diagnostic_to_string(diagnostic, file_manager)); } @@ -450,7 +450,7 @@ impl Formatter for JsonFormatter { TestStatus::CompileError(diagnostic) => { json.insert("event".to_string(), json!("failed")); - if !(diagnostic.diagnostic.is_warning() && silence_warnings) { + if !(diagnostic.is_warning() && silence_warnings) { if !stdout.is_empty() { stdout.push('\n'); } @@ -515,12 +515,11 @@ fn package_start(package_name: &str, test_count: usize) -> std::io::Result<()> { } pub(crate) fn diagnostic_to_string( - file_diagnostic: &FileDiagnostic, + custom_diagnostic: &CustomDiagnostic, file_manager: &FileManager, ) -> String { let file_map = file_manager.as_file_map(); - let custom_diagnostic = &file_diagnostic.diagnostic; let mut message = String::new(); message.push_str(custom_diagnostic.message.trim()); @@ -529,7 +528,7 @@ pub(crate) fn diagnostic_to_string( message.push_str(note.trim()); } - if let Ok(name) = file_map.get_name(file_diagnostic.file_id) { + if let Ok(name) = file_map.get_name(custom_diagnostic.file) { message.push('\n'); message.push_str(&format!("at {name}")); } diff --git a/tooling/nargo_cli/src/errors.rs b/tooling/nargo_cli/src/errors.rs index 055925b467e..fb241bcbd29 100644 --- a/tooling/nargo_cli/src/errors.rs +++ b/tooling/nargo_cli/src/errors.rs @@ -1,8 +1,8 @@ use acvm::FieldElement; -use nargo::{errors::CompileError, NargoError}; +use nargo::{NargoError, errors::CompileError}; use nargo_toml::ManifestError; use noir_debugger::errors::DapError; -use noirc_abi::{errors::AbiError, input_parser::InputValue, AbiReturnType}; +use noirc_abi::errors::AbiError; use std::path::PathBuf; use thiserror::Error; @@ -42,10 +42,4 @@ pub(crate) enum CliError { /// Error from the compilation pipeline #[error(transparent)] CompileError(#[from] CompileError), - - #[error("Unexpected return value: expected {expected:?}; got {actual:?}")] - UnexpectedReturn { expected: InputValue, actual: Option }, - - #[error("Missing return witnesses; expected {expected:?}")] - MissingReturn { expected: AbiReturnType }, } diff --git a/tooling/nargo_cli/src/main.rs b/tooling/nargo_cli/src/main.rs index 3ea167b7ffa..f4cc74447bc 100644 --- a/tooling/nargo_cli/src/main.rs +++ b/tooling/nargo_cli/src/main.rs @@ -15,7 +15,7 @@ use std::env; use color_eyre::config::HookBuilder; use tracing_appender::rolling; -use tracing_subscriber::{fmt::format::FmtSpan, EnvFilter}; +use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan}; const PANIC_MESSAGE: &str = "This is a bug. We may have already fixed this in newer versions of Nargo so try searching for similar issues at https://github.com/noir-lang/noir/issues/.\nIf there isn't an open issue for this bug, consider opening one at https://github.com/noir-lang/noir/issues/new?labels=bug&template=bug_report.yml"; diff --git a/tooling/nargo_cli/tests/stdlib-props.rs b/tooling/nargo_cli/tests/stdlib-props.rs index 780b34bf0c3..2e153b85ba8 100644 --- a/tooling/nargo_cli/tests/stdlib-props.rs +++ b/tooling/nargo_cli/tests/stdlib-props.rs @@ -1,12 +1,12 @@ use std::{cell::RefCell, collections::BTreeMap, path::Path}; -use acvm::{acir::native_types::WitnessStack, AcirField, FieldElement}; +use acvm::{AcirField, FieldElement, acir::native_types::WitnessStack}; use iter_extended::vecmap; use nargo::{foreign_calls::DefaultForeignCallBuilder, ops::execute_program, parse_all}; use noirc_abi::input_parser::InputValue; use noirc_driver::{ - compile_main, file_manager_with_stdlib, prepare_crate, CompilationResult, CompileOptions, - CompiledProgram, CrateId, + CompilationResult, CompileOptions, CompiledProgram, CrateId, compile_main, + file_manager_with_stdlib, prepare_crate, }; use noirc_frontend::hir::Context; use proptest::prelude::*; diff --git a/tooling/nargo_cli/tests/stdlib-tests.rs b/tooling/nargo_cli/tests/stdlib-tests.rs index 2e3e3e2ae5a..6096b619e57 100644 --- a/tooling/nargo_cli/tests/stdlib-tests.rs +++ b/tooling/nargo_cli/tests/stdlib-tests.rs @@ -2,15 +2,15 @@ #![allow(clippy::items_after_test_module)] use clap::Parser; use fm::FileManager; -use nargo::foreign_calls::DefaultForeignCallBuilder; use nargo::PrintOutput; -use noirc_driver::{check_crate, file_manager_with_stdlib, CompileOptions}; +use nargo::foreign_calls::DefaultForeignCallBuilder; +use noirc_driver::{CompileOptions, check_crate, file_manager_with_stdlib}; use noirc_frontend::hir::FunctionNameMatch; use std::io::Write; use std::{collections::BTreeMap, path::PathBuf}; use nargo::{ - ops::{report_errors, run_test, TestStatus}, + ops::{TestStatus, report_errors, run_test}, package::{Package, PackageType}, parse_all, prepare_package, }; diff --git a/tooling/nargo_fmt/src/chunks.rs b/tooling/nargo_fmt/src/chunks.rs index facf23f0ff1..28e6d22f2c8 100644 --- a/tooling/nargo_fmt/src/chunks.rs +++ b/tooling/nargo_fmt/src/chunks.rs @@ -113,11 +113,7 @@ impl Chunk { /// Returns the current chunk as a Group, if it is one. Otherwise returns None. pub(crate) fn group(self) -> Option { - if let Chunk::Group(group) = self { - Some(group) - } else { - None - } + if let Chunk::Group(group) = self { Some(group) } else { None } } } diff --git a/tooling/nargo_fmt/src/config.rs b/tooling/nargo_fmt/src/config.rs index f01afc87af2..3950d267c5e 100644 --- a/tooling/nargo_fmt/src/config.rs +++ b/tooling/nargo_fmt/src/config.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::errors::ConfigError; macro_rules! config { - ($($field_name:ident: $field_ty:ty, $default_value:expr, $description:expr );+ $(;)*) => ( + ($($field_name:ident: $field_ty:ty, $default_value:expr_2021, $description:expr_2021 );+ $(;)*) => ( pub struct Config { $( #[doc = $description] diff --git a/tooling/nargo_fmt/src/formatter.rs b/tooling/nargo_fmt/src/formatter.rs index 5948626dae4..cff0b2c0619 100644 --- a/tooling/nargo_fmt/src/formatter.rs +++ b/tooling/nargo_fmt/src/formatter.rs @@ -1,10 +1,10 @@ use buffer::Buffer; use noirc_frontend::{ + ParsedModule, ast::Ident, hir::resolution::errors::Span, lexer::Lexer, token::{Keyword, SpannedToken, Token}, - ParsedModule, }; use crate::Config; diff --git a/tooling/nargo_fmt/src/formatter/expression.rs b/tooling/nargo_fmt/src/formatter/expression.rs index b83c06724e4..6b46a4557a2 100644 --- a/tooling/nargo_fmt/src/formatter/expression.rs +++ b/tooling/nargo_fmt/src/formatter/expression.rs @@ -1344,7 +1344,7 @@ fn force_if_chunks_to_multiple_lines(group: &mut ChunkGroup, group_tag: GroupTag #[cfg(test)] mod tests { - use crate::{assert_format, assert_format_with_config, assert_format_with_max_width, Config}; + use crate::{Config, assert_format, assert_format_with_config, assert_format_with_max_width}; #[test] fn format_unit() { diff --git a/tooling/nargo_fmt/src/formatter/module.rs b/tooling/nargo_fmt/src/formatter/module.rs index 6bf4e30786d..b2cb250a90a 100644 --- a/tooling/nargo_fmt/src/formatter/module.rs +++ b/tooling/nargo_fmt/src/formatter/module.rs @@ -1,5 +1,5 @@ use noirc_frontend::{ - ast::ModuleDeclaration, parser::ParsedSubModule, token::Keyword, ParsedModule, + ParsedModule, ast::ModuleDeclaration, parser::ParsedSubModule, token::Keyword, }; use super::Formatter; @@ -47,7 +47,7 @@ fn parsed_module_is_empty(parsed_module: &ParsedModule) -> bool { #[cfg(test)] mod tests { - use crate::{assert_format, assert_format_with_config, Config}; + use crate::{Config, assert_format, assert_format_with_config}; #[test] fn format_module_declaration() { diff --git a/tooling/nargo_fmt/src/formatter/pattern.rs b/tooling/nargo_fmt/src/formatter/pattern.rs index e8c6f9f1ec2..f0f94dfa767 100644 --- a/tooling/nargo_fmt/src/formatter/pattern.rs +++ b/tooling/nargo_fmt/src/formatter/pattern.rs @@ -93,11 +93,7 @@ impl Formatter<'_> { } fn is_identifier_pattern(pattern: &Pattern, ident: &Ident) -> bool { - if let Pattern::Identifier(pattern_ident) = pattern { - pattern_ident == ident - } else { - false - } + if let Pattern::Identifier(pattern_ident) = pattern { pattern_ident == ident } else { false } } #[cfg(test)] diff --git a/tooling/nargo_fmt/src/formatter/traits.rs b/tooling/nargo_fmt/src/formatter/traits.rs index 7381dee35d7..8195a30c296 100644 --- a/tooling/nargo_fmt/src/formatter/traits.rs +++ b/tooling/nargo_fmt/src/formatter/traits.rs @@ -4,7 +4,7 @@ use noirc_frontend::{ token::{Attributes, Keyword, Token}, }; -use super::{function::FunctionToFormat, Formatter}; +use super::{Formatter, function::FunctionToFormat}; impl Formatter<'_> { pub(super) fn format_trait(&mut self, noir_trait: NoirTrait) { diff --git a/tooling/nargo_fmt/src/formatter/use_tree.rs b/tooling/nargo_fmt/src/formatter/use_tree.rs index 5fd6aada664..471dd00ca30 100644 --- a/tooling/nargo_fmt/src/formatter/use_tree.rs +++ b/tooling/nargo_fmt/src/formatter/use_tree.rs @@ -121,7 +121,7 @@ impl ChunkFormatter<'_, '_> { #[cfg(test)] mod tests { - use crate::{assert_format_with_config, config::ImportsGranularity, Config}; + use crate::{Config, assert_format_with_config, config::ImportsGranularity}; fn assert_format(src: &str, expected: &str) { let config = Config { diff --git a/tooling/nargo_fmt/src/formatter/use_tree_merge.rs b/tooling/nargo_fmt/src/formatter/use_tree_merge.rs index ca6d64ea89b..f64b0cb128e 100644 --- a/tooling/nargo_fmt/src/formatter/use_tree_merge.rs +++ b/tooling/nargo_fmt/src/formatter/use_tree_merge.rs @@ -180,11 +180,7 @@ impl Ord for Segment { if let (Segment::Plain(self_string), Segment::Plain(other_string)) = (self, other) { // Case-insensitive comparison for plain segments let ordering = self_string.to_lowercase().cmp(&other_string.to_lowercase()); - if ordering == Ordering::Equal { - self_string.cmp(other_string) - } else { - ordering - } + if ordering == Ordering::Equal { self_string.cmp(other_string) } else { ordering } } else { order_number_ordering } @@ -299,7 +295,7 @@ fn merge_imports_in_tree(imports: Vec, mut tree: &mut ImportTree) { #[cfg(test)] mod tests { - use crate::{assert_format_with_config, config::ImportsGranularity, Config}; + use crate::{Config, assert_format_with_config, config::ImportsGranularity}; fn assert_format(src: &str, expected: &str) { let config = Config { diff --git a/tooling/nargo_toml/src/lib.rs b/tooling/nargo_toml/src/lib.rs index 3a4d5e2d9b5..b62884f28c4 100644 --- a/tooling/nargo_toml/src/lib.rs +++ b/tooling/nargo_toml/src/lib.rs @@ -9,7 +9,7 @@ use std::{ }; use errors::SemverError; -use fm::{NormalizePath, FILE_EXTENSION}; +use fm::{FILE_EXTENSION, NormalizePath}; use nargo::{ package::{Dependency, Package, PackageType}, workspace::Workspace, @@ -52,11 +52,7 @@ pub fn find_file_manifest(current_path: &Path) -> Option { /// /// Returns a [ManifestError] if no parent directories of `current_path` contain a manifest file. pub fn find_root(current_path: &Path, workspace: bool) -> Result { - if workspace { - find_package_root(current_path) - } else { - find_file_root(current_path) - } + if workspace { find_package_root(current_path) } else { find_file_root(current_path) } } /// Returns the [PathBuf] of the directory containing the `Nargo.toml` by searching from `current_path` to the root of its [Path], @@ -540,7 +536,7 @@ mod tests { use test_case::test_matrix; - use crate::{find_root, Config, ManifestError}; + use crate::{Config, ManifestError, find_root}; #[test] fn parse_standard_toml() { diff --git a/tooling/nargo_toml/src/semver.rs b/tooling/nargo_toml/src/semver.rs index 02a7488379b..83f31c71a5e 100644 --- a/tooling/nargo_toml/src/semver.rs +++ b/tooling/nargo_toml/src/semver.rs @@ -1,4 +1,4 @@ -use crate::{errors::SemverError, ManifestError}; +use crate::{ManifestError, errors::SemverError}; use nargo::{ package::{Dependency, Package}, workspace::Workspace, diff --git a/tooling/noirc_abi/src/arbitrary.rs b/tooling/noirc_abi/src/arbitrary.rs index 1e83a76e1c5..ff0c2f5eed2 100644 --- a/tooling/noirc_abi/src/arbitrary.rs +++ b/tooling/noirc_abi/src/arbitrary.rs @@ -5,8 +5,8 @@ use proptest::prelude::*; use acvm::{AcirField, FieldElement}; use crate::{ - input_parser::InputValue, Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, InputMap, - Sign, + Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, InputMap, Sign, + input_parser::InputValue, }; use std::collections::{BTreeMap, HashSet}; diff --git a/tooling/noirc_abi/src/errors.rs b/tooling/noirc_abi/src/errors.rs index 3e19f5c7d82..f08f7b21721 100644 --- a/tooling/noirc_abi/src/errors.rs +++ b/tooling/noirc_abi/src/errors.rs @@ -1,8 +1,8 @@ use crate::{ - input_parser::{InputTypecheckingError, InputValue}, AbiType, + input_parser::{InputTypecheckingError, InputValue}, }; -use acvm::{acir::native_types::Witness, AcirField, FieldElement}; +use acvm::{AcirField, FieldElement, acir::native_types::Witness}; use thiserror::Error; #[derive(Debug, Error)] diff --git a/tooling/noirc_abi/src/input_parser/json.rs b/tooling/noirc_abi/src/input_parser/json.rs index 7b2e8be454b..f8b73ad05a5 100644 --- a/tooling/noirc_abi/src/input_parser/json.rs +++ b/tooling/noirc_abi/src/input_parser/json.rs @@ -1,8 +1,8 @@ use super::{ - field_to_signed_hex, parse_integer_to_signed, parse_str_to_field, parse_str_to_signed, - InputValue, + InputValue, field_to_signed_hex, parse_integer_to_signed, parse_str_to_field, + parse_str_to_signed, }; -use crate::{errors::InputParserError, Abi, AbiType, MAIN_RETURN_NAME}; +use crate::{Abi, AbiType, MAIN_RETURN_NAME, errors::InputParserError}; use acvm::{AcirField, FieldElement}; use iter_extended::{try_btree_map, try_vecmap}; use serde::{Deserialize, Serialize}; @@ -225,9 +225,9 @@ mod test { use proptest::prelude::*; use crate::{ - arbitrary::arb_abi_and_input_map, - input_parser::{arbitrary::arb_signed_integer_type_and_value, json::JsonTypes, InputValue}, AbiType, + arbitrary::arb_abi_and_input_map, + input_parser::{InputValue, arbitrary::arb_signed_integer_type_and_value, json::JsonTypes}, }; use super::{parse_json, serialize_to_json}; diff --git a/tooling/noirc_abi/src/input_parser/mod.rs b/tooling/noirc_abi/src/input_parser/mod.rs index 8e90832f9fc..72aef1f48bb 100644 --- a/tooling/noirc_abi/src/input_parser/mod.rs +++ b/tooling/noirc_abi/src/input_parser/mod.rs @@ -248,8 +248,8 @@ mod serialization_tests { use strum::IntoEnumIterator; use crate::{ - input_parser::InputValue, Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, Sign, - MAIN_RETURN_NAME, + Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, MAIN_RETURN_NAME, Sign, + input_parser::InputValue, }; use super::Format; @@ -467,7 +467,7 @@ mod test { use num_bigint::BigUint; use strum::IntoEnumIterator; - use super::{parse_str_to_field, parse_str_to_signed, Format}; + use super::{Format, parse_str_to_field, parse_str_to_signed}; fn big_uint_from_field(field: FieldElement) -> BigUint { BigUint::from_bytes_be(&field.to_be_bytes()) diff --git a/tooling/noirc_abi/src/input_parser/toml.rs b/tooling/noirc_abi/src/input_parser/toml.rs index aaa3358f4fc..2e2d12f853c 100644 --- a/tooling/noirc_abi/src/input_parser/toml.rs +++ b/tooling/noirc_abi/src/input_parser/toml.rs @@ -1,8 +1,8 @@ use super::{ - field_to_signed_hex, parse_integer_to_signed, parse_str_to_field, parse_str_to_signed, - InputValue, + InputValue, field_to_signed_hex, parse_integer_to_signed, parse_str_to_field, + parse_str_to_signed, }; -use crate::{errors::InputParserError, Abi, AbiType, MAIN_RETURN_NAME}; +use crate::{Abi, AbiType, MAIN_RETURN_NAME, errors::InputParserError}; use acvm::{AcirField, FieldElement}; use iter_extended::{try_btree_map, try_vecmap}; use serde::{Deserialize, Serialize}; @@ -210,9 +210,9 @@ mod test { use proptest::prelude::*; use crate::{ - arbitrary::arb_abi_and_input_map, - input_parser::{arbitrary::arb_signed_integer_type_and_value, toml::TomlTypes, InputValue}, AbiType, + arbitrary::arb_abi_and_input_map, + input_parser::{InputValue, arbitrary::arb_signed_integer_type_and_value, toml::TomlTypes}, }; use super::{parse_toml, serialize_to_toml}; diff --git a/tooling/noirc_abi/src/lib.rs b/tooling/noirc_abi/src/lib.rs index 99428849cbc..17f9a07c221 100644 --- a/tooling/noirc_abi/src/lib.rs +++ b/tooling/noirc_abi/src/lib.rs @@ -4,11 +4,11 @@ #![warn(clippy::semicolon_if_nothing_returned)] use acvm::{ + AcirField, FieldElement, acir::{ circuit::ErrorSelector, native_types::{Witness, WitnessMap}, }, - AcirField, FieldElement, }; use errors::AbiError; use input_parser::InputValue; diff --git a/tooling/noirc_abi_wasm/src/js_witness_map.rs b/tooling/noirc_abi_wasm/src/js_witness_map.rs index 018352c3405..8b751426ac2 100644 --- a/tooling/noirc_abi_wasm/src/js_witness_map.rs +++ b/tooling/noirc_abi_wasm/src/js_witness_map.rs @@ -1,11 +1,11 @@ //! This can most likely be imported from acvm_js to avoid redefining it here. use acvm::{ - acir::native_types::{Witness, WitnessMap}, AcirField, FieldElement, + acir::native_types::{Witness, WitnessMap}, }; use js_sys::{JsString, Map}; -use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; +use wasm_bindgen::prelude::{JsValue, wasm_bindgen}; // WitnessMap #[wasm_bindgen] @@ -72,8 +72,8 @@ mod test { use std::collections::BTreeMap; use acvm::{ - acir::native_types::{Witness, WitnessMap}, AcirField, FieldElement, + acir::native_types::{Witness, WitnessMap}, }; use wasm_bindgen::JsValue; diff --git a/tooling/noirc_abi_wasm/src/lib.rs b/tooling/noirc_abi_wasm/src/lib.rs index 79aecafa742..390f4353bb2 100644 --- a/tooling/noirc_abi_wasm/src/lib.rs +++ b/tooling/noirc_abi_wasm/src/lib.rs @@ -6,24 +6,23 @@ use getrandom as _; use acvm::{ + FieldElement, acir::{ circuit::RawAssertionPayload, native_types::{WitnessMap, WitnessStack}, }, - FieldElement, }; use iter_extended::try_btree_map; use noirc_abi::{ - decode_value, display_abi_error, + Abi, AbiErrorType, MAIN_RETURN_NAME, decode_value, display_abi_error, errors::InputParserError, - input_parser::{json::JsonTypes, InputValue}, - Abi, AbiErrorType, MAIN_RETURN_NAME, + input_parser::{InputValue, json::JsonTypes}, }; use serde::Serialize; use std::collections::BTreeMap; use gloo_utils::format::JsValueSerdeExt; -use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; +use wasm_bindgen::{JsValue, prelude::wasm_bindgen}; mod errors; mod js_witness_map; diff --git a/tooling/noirc_artifacts/src/contract.rs b/tooling/noirc_artifacts/src/contract.rs index e2ca8ec4025..9f8f7019ff1 100644 --- a/tooling/noirc_artifacts/src/contract.rs +++ b/tooling/noirc_artifacts/src/contract.rs @@ -1,6 +1,6 @@ -use acvm::{acir::circuit::Program, FieldElement}; +use acvm::{FieldElement, acir::circuit::Program}; use noirc_abi::{Abi, AbiType, AbiValue}; -use noirc_driver::{CompiledContract, CompiledContractOutputs, ContractFunction}; +use noirc_driver::{CompiledContract, CompiledContractOutputs, CompiledProgram, ContractFunction}; use serde::{Deserialize, Serialize}; use noirc_driver::DebugFile; @@ -49,6 +49,14 @@ impl From for ContractArtifact { } } +impl ContractArtifact { + pub fn function_as_compiled_program(&self, function_name: &str) -> Option { + self.functions.iter().find(|f| f.name == function_name).map(|f| { + f.clone().into_compiled_program(self.noir_version.clone(), self.file_map.clone()) + }) + } +} + /// Each function in the contract will be compiled as a separate noir program. /// /// A contract function unlike a regular Noir program however can have additional properties. @@ -85,6 +93,26 @@ pub struct ContractFunctionArtifact { pub brillig_names: Vec, } +impl ContractFunctionArtifact { + pub fn into_compiled_program( + self, + noir_version: String, + file_map: BTreeMap, + ) -> CompiledProgram { + CompiledProgram { + noir_version, + hash: self.hash, + program: self.bytecode, + abi: self.abi, + debug: self.debug_symbols.debug_infos, + file_map, + warnings: Vec::new(), + names: self.names, + brillig_names: self.brillig_names, + } + } +} + impl From for ContractFunctionArtifact { fn from(func: ContractFunction) -> Self { ContractFunctionArtifact { diff --git a/tooling/noirc_artifacts/src/debug.rs b/tooling/noirc_artifacts/src/debug.rs index 5c47f1f2652..4924a9f1ca1 100644 --- a/tooling/noirc_artifacts/src/debug.rs +++ b/tooling/noirc_artifacts/src/debug.rs @@ -1,6 +1,6 @@ use codespan_reporting::files::{Error, Files, SimpleFile}; use noirc_driver::{CompiledContract, CompiledProgram, DebugFile}; -use noirc_errors::{debug_info::DebugInfo, Location}; +use noirc_errors::{Location, debug_info::DebugInfo}; use serde::{Deserialize, Serialize}; use std::{ collections::{BTreeMap, BTreeSet}, @@ -204,12 +204,12 @@ mod tests { use crate::debug::DebugArtifact; use acvm::acir::circuit::OpcodeLocation; use fm::FileManager; - use noirc_errors::{debug_info::DebugInfo, Location, Span}; + use noirc_errors::{Location, Span, debug_info::DebugInfo}; use std::collections::BTreeMap; use std::ops::Range; use std::path::Path; use std::path::PathBuf; - use tempfile::{tempdir, TempDir}; + use tempfile::{TempDir, tempdir}; // Returns the absolute path to the file fn create_dummy_file(dir: &TempDir, file_name: &Path) -> PathBuf { diff --git a/tooling/noirc_artifacts/src/lib.rs b/tooling/noirc_artifacts/src/lib.rs index 7bd2ed997ae..337d5d8550d 100644 --- a/tooling/noirc_artifacts/src/lib.rs +++ b/tooling/noirc_artifacts/src/lib.rs @@ -9,7 +9,7 @@ //! Should any projects require/desire a different artifact format, it's expected that they will write a transformer //! to generate them using these artifacts as a starting point. -use serde::{de::Visitor, Deserializer, Serializer}; +use serde::{Deserializer, Serializer, de::Visitor}; pub mod contract; pub mod debug; diff --git a/tooling/noirc_artifacts/src/program.rs b/tooling/noirc_artifacts/src/program.rs index 5d1ce17a8d1..fc452fcb2af 100644 --- a/tooling/noirc_artifacts/src/program.rs +++ b/tooling/noirc_artifacts/src/program.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; -use acvm::acir::circuit::Program; use acvm::FieldElement; +use acvm::acir::circuit::Program; use fm::FileId; use noirc_abi::Abi; use noirc_driver::CompiledProgram; diff --git a/tooling/noirc_artifacts_info/src/lib.rs b/tooling/noirc_artifacts_info/src/lib.rs index 6f4c80accbd..b1db98f2157 100644 --- a/tooling/noirc_artifacts_info/src/lib.rs +++ b/tooling/noirc_artifacts_info/src/lib.rs @@ -1,7 +1,7 @@ use acvm::acir::circuit::ExpressionWidth; use iter_extended::vecmap; use noirc_artifacts::program::ProgramArtifact; -use prettytable::{row, table, Row}; +use prettytable::{Row, row, table}; use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; use serde::Serialize; diff --git a/tooling/profiler/src/cli/execution_flamegraph_cmd.rs b/tooling/profiler/src/cli/execution_flamegraph_cmd.rs index 0dfcf8b516c..c9d7eca50f5 100644 --- a/tooling/profiler/src/cli/execution_flamegraph_cmd.rs +++ b/tooling/profiler/src/cli/execution_flamegraph_cmd.rs @@ -4,14 +4,14 @@ use acir::circuit::Opcode; use acir::circuit::OpcodeLocation; use clap::Args; use color_eyre::eyre::{self, Context}; +use nargo::PrintOutput; use nargo::errors::try_to_diagnose_runtime_error; use nargo::foreign_calls::DefaultForeignCallBuilder; -use nargo::PrintOutput; use noir_artifact_cli::fs::artifact::read_program_from_file; use noir_artifact_cli::fs::inputs::read_inputs_from_file; use noirc_artifacts::program::ProgramArtifact; -use crate::errors::{report_error, CliError}; +use crate::errors::{CliError, report_error}; use crate::flamegraph::{BrilligExecutionSample, FlamegraphGenerator, InfernoFlamegraphGenerator}; use crate::opcode_formatter::format_brillig_opcode; use bn254_blackbox_solver::Bn254BlackBoxSolver; diff --git a/tooling/profiler/src/cli/gates_flamegraph_cmd.rs b/tooling/profiler/src/cli/gates_flamegraph_cmd.rs index a82e5ea3e2a..736cddf7cf4 100644 --- a/tooling/profiler/src/cli/gates_flamegraph_cmd.rs +++ b/tooling/profiler/src/cli/gates_flamegraph_cmd.rs @@ -125,7 +125,7 @@ fn run_with_provider( #[cfg(test)] mod tests { use acir::circuit::{Circuit, Program}; - use color_eyre::eyre::{self}; + use color_eyre::eyre; use fm::codespan_files::Files; use noirc_artifacts::program::ProgramArtifact; use noirc_errors::debug_info::{DebugInfo, ProgramDebugInfo}; diff --git a/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs b/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs index b909097a9a7..8ce9ba1de39 100644 --- a/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs +++ b/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs @@ -154,13 +154,13 @@ fn locate_brillig_call( #[cfg(test)] mod tests { use acir::{ + FieldElement, circuit::{ - brillig::{BrilligBytecode, BrilligFunctionId}, Circuit, Opcode, Program, + brillig::{BrilligBytecode, BrilligFunctionId}, }, - FieldElement, }; - use color_eyre::eyre::{self}; + use color_eyre::eyre; use fm::codespan_files::Files; use noirc_artifacts::program::ProgramArtifact; use noirc_errors::debug_info::{DebugInfo, ProgramDebugInfo}; diff --git a/tooling/profiler/src/flamegraph.rs b/tooling/profiler/src/flamegraph.rs index 192539d6517..16857eb2454 100644 --- a/tooling/profiler/src/flamegraph.rs +++ b/tooling/profiler/src/flamegraph.rs @@ -1,15 +1,15 @@ use std::path::Path; use std::{collections::BTreeMap, io::BufWriter}; -use acir::circuit::brillig::BrilligFunctionId; use acir::circuit::OpcodeLocation; -use color_eyre::eyre::{self}; +use acir::circuit::brillig::BrilligFunctionId; +use color_eyre::eyre; use fm::codespan_files::Files; use fxhash::FxHashMap as HashMap; -use inferno::flamegraph::{from_lines, Options, TextTruncateDirection}; +use inferno::flamegraph::{Options, TextTruncateDirection, from_lines}; +use noirc_errors::Location; use noirc_errors::debug_info::DebugInfo; use noirc_errors::reporter::line_and_column_from_span; -use noirc_errors::Location; use noirc_evaluator::brillig::ProcedureId; pub(crate) trait Sample { @@ -293,12 +293,12 @@ fn to_folded_sorted_lines( #[cfg(test)] mod tests { use acir::{ - circuit::{opcodes::BlockId, Opcode as AcirOpcode, OpcodeLocation}, - native_types::Expression, FieldElement, + circuit::{Opcode as AcirOpcode, OpcodeLocation, opcodes::BlockId}, + native_types::Expression, }; use fm::FileManager; - use noirc_errors::{debug_info::DebugInfo, Location, Span}; + use noirc_errors::{Location, Span, debug_info::DebugInfo}; use std::{collections::BTreeMap, path::Path}; use crate::{flamegraph::CompilationSample, opcode_formatter::format_acir_opcode}; diff --git a/tooling/profiler/src/gates_provider.rs b/tooling/profiler/src/gates_provider.rs index 3f07f3e4be6..044e2a3642c 100644 --- a/tooling/profiler/src/gates_provider.rs +++ b/tooling/profiler/src/gates_provider.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; -use color_eyre::eyre::{self}; +use color_eyre::eyre; use serde::{Deserialize, Serialize}; pub(crate) trait GatesProvider { diff --git a/tooling/profiler/src/main.rs b/tooling/profiler/src/main.rs index 47cc9576b2f..e4a5bc153d2 100644 --- a/tooling/profiler/src/main.rs +++ b/tooling/profiler/src/main.rs @@ -12,7 +12,7 @@ mod opcode_formatter; use std::env; use tracing_appender::rolling; -use tracing_subscriber::{fmt::format::FmtSpan, EnvFilter}; +use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan}; fn main() { // Setup tracing diff --git a/tooling/profiler/src/opcode_formatter.rs b/tooling/profiler/src/opcode_formatter.rs index d1081de6c8f..2276bcb4403 100644 --- a/tooling/profiler/src/opcode_formatter.rs +++ b/tooling/profiler/src/opcode_formatter.rs @@ -1,6 +1,6 @@ -use acir::brillig::{BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode}; -use acir::circuit::{opcodes::BlackBoxFuncCall, Opcode as AcirOpcode}; use acir::AcirField; +use acir::brillig::{BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode}; +use acir::circuit::{Opcode as AcirOpcode, opcodes::BlackBoxFuncCall}; fn format_blackbox_function(call: &BlackBoxFuncCall) -> String { match call {