diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 3bc99b4d054..ddafc0bb570 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -307,6 +307,7 @@ impl AcirContext { inverse_code, vec![AcirValue::Var(var, AcirType::field())], vec![AcirType::field()], + true, )?; let inverted_var = Self::expect_one_var(results); @@ -708,6 +709,7 @@ impl AcirContext { AcirValue::Var(rhs, AcirType::unsigned(bit_size)), ], vec![AcirType::unsigned(max_q_bits), AcirType::unsigned(max_rhs_bits)], + true, )? .try_into() .expect("quotient only returns two values"); @@ -1310,6 +1312,7 @@ impl AcirContext { generated_brillig: GeneratedBrillig, inputs: Vec, outputs: Vec, + attempt_execution: bool, ) -> Result, InternalError> { let b_inputs = try_vecmap(inputs, |i| match i { AcirValue::Var(var, _) => Ok(BrilligInputs::Single(self.var_to_expression(var)?)), @@ -1329,10 +1332,15 @@ impl AcirContext { // Optimistically try executing the brillig now, if we can complete execution they just return the results. // This is a temporary measure pending SSA optimizations being applied to Brillig which would remove constant-input opcodes (See #2066) - if let Some(brillig_outputs) = - self.execute_brillig(&generated_brillig.byte_code, &b_inputs, &outputs) - { - return Ok(brillig_outputs); + // + // We do _not_ want to do this in the situation where the `main` function is unconstrained, as if execution succeeds + // the entire program will be replaced with witness constraints to its outputs. + if attempt_execution { + if let Some(brillig_outputs) = + self.execute_brillig(&generated_brillig.byte_code, &b_inputs, &outputs) + { + return Ok(brillig_outputs); + } } // Otherwise we must generate ACIR for it and execute at runtime. diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 33f00796c9d..edf0461430f 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -266,11 +266,14 @@ impl Context { let code = self.gen_brillig_for(main_func, &brillig)?; + // We specifically do not attempt execution of the brillig code being generated as this can result in it being + // replaced with constraints on witnesses to the program outputs. let output_values = self.acir_context.brillig( self.current_side_effects_enabled_var, code, inputs, outputs, + false, )?; let output_vars: Vec<_> = output_values .iter() @@ -489,7 +492,7 @@ impl Context { let outputs: Vec = vecmap(result_ids, |result_id| dfg.type_of_value(*result_id).into()); - let output_values = self.acir_context.brillig(self.current_side_effects_enabled_var, code, inputs, outputs)?; + let output_values = self.acir_context.brillig(self.current_side_effects_enabled_var, code, inputs, outputs, true)?; // Compiler sanity check assert_eq!(result_ids.len(), output_values.len(), "ICE: The number of Brillig output values should match the result ids in SSA"); diff --git a/compiler/noirc_frontend/src/hir_def/traits.rs b/compiler/noirc_frontend/src/hir_def/traits.rs index ea9c2e2928c..7bf5870e1f5 100644 --- a/compiler/noirc_frontend/src/hir_def/traits.rs +++ b/compiler/noirc_frontend/src/hir_def/traits.rs @@ -6,7 +6,7 @@ use crate::{ Generics, Ident, NoirFunction, Type, TypeVariable, TypeVariableId, }; use fm::FileId; -use noirc_errors::Span; +use noirc_errors::{Location, Span}; #[derive(Clone, Debug, PartialEq, Eq)] pub struct TraitFunction { @@ -56,7 +56,7 @@ pub struct Trait { pub name: Ident, pub generics: Generics, - pub span: Span, + pub location: Location, /// When resolving the types of Trait elements, all references to `Self` resolve /// to this TypeVariable. Then when we check if the types of trait impl elements diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 9082df1bcd5..261b11158cf 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -468,6 +468,7 @@ impl NodeInterner { /// The [Location] may not necessarily point to the beginning of the item /// so we check if the location's span is contained within the start or end /// of each items [Span] + #[tracing::instrument(skip(self))] pub fn find_location_index(&self, location: Location) -> Option> { let mut location_candidate: Option<(&Index, &Location)> = None; @@ -504,7 +505,7 @@ impl NodeInterner { id: type_id, name: unresolved_trait.trait_def.name.clone(), crate_id: unresolved_trait.crate_id, - span: unresolved_trait.trait_def.span, + location: Location::new(unresolved_trait.trait_def.span, unresolved_trait.file_id), generics: vecmap(&unresolved_trait.trait_def.generics, |_| { // Temporary type variable ids before the trait is resolved to its actual ids. // This lets us record how many arguments the type expects so that other types @@ -1142,6 +1143,7 @@ impl NodeInterner { } /// Adds a trait implementation to the list of known implementations. + #[tracing::instrument(skip(self))] pub fn add_trait_implementation( &mut self, object_type: Type, @@ -1274,7 +1276,9 @@ impl NodeInterner { /// Returns the [Location] of the definition of the given Ident found at [Span] of the given [FileId]. /// Returns [None] when definition is not found. pub fn get_definition_location_from(&self, location: Location) -> Option { - self.find_location_index(location).and_then(|index| self.resolve_location(index)) + self.find_location_index(location) + .and_then(|index| self.resolve_location(index)) + .or_else(|| self.try_resolve_trait_impl_location(location)) } /// For a given [Index] we return [Location] to which we resolved to @@ -1429,6 +1433,24 @@ impl NodeInterner { pub(crate) fn ordering_type(&self) -> Type { self.ordering_type.clone().expect("Expected ordering_type to be set in the NodeInterner") } + + /// Attempts to resolve [Location] of [Trait] based on [Location] of [TraitImpl] + /// This is used by LSP to resolve the location of a trait based on the location of a trait impl. + /// + /// Example: + /// impl Foo for Bar { ... } -> trait Foo { ... } + fn try_resolve_trait_impl_location(&self, location: Location) -> Option { + self.trait_implementations + .iter() + .find(|shared_trait_impl| { + let trait_impl = shared_trait_impl.borrow(); + trait_impl.file == location.file && trait_impl.ident.span().contains(&location.span) + }) + .and_then(|shared_trait_impl| { + let trait_impl = shared_trait_impl.borrow(); + self.traits.get(&trait_impl.trait_id).map(|trait_| trait_.location) + }) + } } impl Methods { diff --git a/noir_stdlib/src/ec/montcurve.nr b/noir_stdlib/src/ec/montcurve.nr index 82d22837b46..83a17bae322 100644 --- a/noir_stdlib/src/ec/montcurve.nr +++ b/noir_stdlib/src/ec/montcurve.nr @@ -12,6 +12,8 @@ mod affine { use crate::ec::safe_inverse; use crate::ec::sqrt; use crate::ec::ZETA; + use crate::cmp::Eq; + // Curve specification struct Curve { // Montgomery Curve configuration (ky^2 = x^3 + j*x^2 + x) j: Field, @@ -32,11 +34,6 @@ mod affine { Self {x, y, infty: false} } - // Check for equality - fn eq(self, p: Self) -> bool { - (self.infty & p.infty) | (!self.infty & !p.infty & (self.x == p.x) & (self.y == p.y)) - } - // Check if zero pub fn is_zero(self) -> bool { self.infty @@ -76,6 +73,12 @@ mod affine { } } + impl Eq for Point { + fn eq(self, p: Self) -> bool { + (self.infty & p.infty) | (!self.infty & !p.infty & (self.x == p.x) & (self.y == p.y)) + } + } + impl Curve { // Curve constructor pub fn new(j: Field, k: Field, gen: Point) -> Self { @@ -219,6 +222,7 @@ mod curvegroup { use crate::ec::swcurve::curvegroup::Point as SWPoint; use crate::ec::tecurve::curvegroup::Curve as TECurve; use crate::ec::tecurve::curvegroup::Point as TEPoint; + use crate::cmp::Eq; struct Curve { // Montgomery Curve configuration (ky^2 z = x*(x^2 + j*x*z + z*z)) j: Field, @@ -239,11 +243,6 @@ mod curvegroup { Self {x, y, z} } - // Check for equality - fn eq(self, p: Self) -> bool { - (self.z == p.z) | (((self.x * self.z) == (p.x * p.z)) & ((self.y * self.z) == (p.y * p.z))) - } - // Check if zero pub fn is_zero(self) -> bool { self.z == 0 @@ -277,6 +276,12 @@ mod curvegroup { } } + impl Eq for Point { + fn eq(self, p: Self) -> bool { + (self.z == p.z) | (((self.x * self.z) == (p.x * p.z)) & ((self.y * self.z) == (p.y * p.z))) + } + } + impl Curve { // Curve constructor pub fn new(j: Field, k: Field, gen: Point) -> Self { diff --git a/noir_stdlib/src/ec/swcurve.nr b/noir_stdlib/src/ec/swcurve.nr index e9b6f661843..e64f5a7be02 100644 --- a/noir_stdlib/src/ec/swcurve.nr +++ b/noir_stdlib/src/ec/swcurve.nr @@ -7,6 +7,8 @@ mod affine { use crate::ec::safe_inverse; use crate::ec::is_square; use crate::ec::sqrt; + use crate::cmp::Eq; + // Curve specification struct Curve { // Short Weierstraß curve // Coefficients in defining equation y^2 = x^3 + ax + b @@ -28,15 +30,6 @@ mod affine { Self {x, y, infty: false} } - // Check for equality - fn eq(self, p: Point) -> bool { - let Self {x: x1, y: y1, infty: inf1} = self; - let Self {x: x2, y: y2, infty: inf2} = p; - - (inf1 & inf2) - | (!inf1 & !inf2 & (x1 == x2) & (y1 == y2)) - } - // Check if zero pub fn is_zero(self) -> bool { self.eq(Point::zero()) @@ -65,6 +58,16 @@ mod affine { } } + impl Eq for Point { + fn eq(self, p: Self) -> bool { + let Self {x: x1, y: y1, infty: inf1} = self; + let Self {x: x2, y: y2, infty: inf2} = p; + + (inf1 & inf2) + | (!inf1 & !inf2 & (x1 == x2) & (y1 == y2)) + } + } + impl Curve { // Curve constructor pub fn new(a: Field, b: Field, gen: Point) -> Curve { @@ -182,6 +185,8 @@ mod curvegroup { // Points are represented by three-dimensional Jacobian coordinates. // See for details. use crate::ec::swcurve::affine; + use crate::cmp::Eq; + // Curve specification struct Curve { // Short Weierstraß curve // Coefficients in defining equation y^2 = x^3 + axz^4 + bz^6 @@ -203,14 +208,6 @@ mod curvegroup { Self {x, y, z} } - // Check for equality - fn eq(self, p: Point) -> bool { - let Self {x: x1, y: y1, z: z1} = self; - let Self {x: x2, y: y2, z: z2} = p; - - ((z1 == 0) & (z2 == 0)) | ((z1 != 0) & (z2 != 0) & (x1*z2*z2 == x2*z1*z1) & (y1*z2*z2*z2 == y2*z1*z1*z1)) - } - // Check if zero pub fn is_zero(self) -> bool { self.eq(Point::zero()) @@ -240,6 +237,15 @@ mod curvegroup { } } + impl Eq for Point { + fn eq(self, p: Self) -> bool { + let Self {x: x1, y: y1, z: z1} = self; + let Self {x: x2, y: y2, z: z2} = p; + + ((z1 == 0) & (z2 == 0)) | ((z1 != 0) & (z2 != 0) & (x1*z2*z2 == x2*z1*z1) & (y1*z2*z2*z2 == y2*z1*z1*z1)) + } + } + impl Curve { // Curve constructor pub fn new(a: Field, b: Field, gen: Point) -> Curve { diff --git a/noir_stdlib/src/ec/tecurve.nr b/noir_stdlib/src/ec/tecurve.nr index 849b45ff012..5333ece4c4a 100644 --- a/noir_stdlib/src/ec/tecurve.nr +++ b/noir_stdlib/src/ec/tecurve.nr @@ -9,6 +9,8 @@ mod affine { use crate::ec::montcurve::affine::Point as MPoint; use crate::ec::swcurve::affine::Curve as SWCurve; use crate::ec::swcurve::affine::Point as SWPoint; + use crate::cmp::Eq; + // Curve specification struct Curve { // Twisted Edwards curve // Coefficients in defining equation ax^2 + y^2 = 1 + dx^2y^2 @@ -29,14 +31,6 @@ mod affine { Self { x, y } } - // Check for equality - fn eq(self, p: Point) -> bool { - let Self {x: x1, y: y1} = self; - let Self {x: x2, y: y2} = p; - - (x1 == x2) & (y1 == y2) - } - // Check if zero pub fn is_zero(self) -> bool { self.eq(Point::zero()) @@ -74,6 +68,15 @@ mod affine { } } + impl Eq for Point { + fn eq(self, p: Self) -> bool { + let Self {x: x1, y: y1} = self; + let Self {x: x2, y: y2} = p; + + (x1 == x2) & (y1 == y2) + } + } + impl Curve { // Curve constructor pub fn new(a: Field, d: Field, gen: Point) -> Curve { @@ -198,6 +201,8 @@ mod curvegroup { use crate::ec::montcurve::curvegroup::Point as MPoint; use crate::ec::swcurve::curvegroup::Curve as SWCurve; use crate::ec::swcurve::curvegroup::Point as SWPoint; + use crate::cmp::Eq; + // Curve specification struct Curve { // Twisted Edwards curve // Coefficients in defining equation a(x^2 + y^2)z^2 = z^4 + dx^2y^2 @@ -220,14 +225,6 @@ mod curvegroup { Self {x, y, t, z} } - // Check for equality - fn eq(self, p: Point) -> bool { - let Self {x: x1, y: y1, t: _t1, z: z1} = self; - let Self {x: x2, y: y2, t: _t2, z:z2} = p; - - (x1*z2 == x2*z1) & (y1*z2 == y2*z1) - } - // Check if zero pub fn is_zero(self) -> bool { let Self {x, y, t, z} = self; @@ -259,6 +256,15 @@ mod curvegroup { } } + impl Eq for Point { + fn eq(self, p: Self) -> bool { + let Self {x: x1, y: y1, t: _t1, z: z1} = self; + let Self {x: x2, y: y2, t: _t2, z:z2} = p; + + (x1*z2 == x2*z1) & (y1*z2 == y2*z1) + } + } + impl Curve { // Curve constructor pub fn new(a: Field, d: Field, gen: Point) -> Curve { diff --git a/test_programs/compile_success_empty/brillig_set_slice_of_slice/Nargo.toml b/test_programs/execution_success/brillig_set_slice_of_slice/Nargo.toml similarity index 100% rename from test_programs/compile_success_empty/brillig_set_slice_of_slice/Nargo.toml rename to test_programs/execution_success/brillig_set_slice_of_slice/Nargo.toml diff --git a/test_programs/compile_success_empty/brillig_set_slice_of_slice/src/main.nr b/test_programs/execution_success/brillig_set_slice_of_slice/src/main.nr similarity index 100% rename from test_programs/compile_success_empty/brillig_set_slice_of_slice/src/main.nr rename to test_programs/execution_success/brillig_set_slice_of_slice/src/main.nr diff --git a/test_programs/compile_success_empty/brillig_to_bits/Nargo.toml b/test_programs/execution_success/brillig_to_bits/Nargo.toml similarity index 100% rename from test_programs/compile_success_empty/brillig_to_bits/Nargo.toml rename to test_programs/execution_success/brillig_to_bits/Nargo.toml diff --git a/test_programs/compile_success_empty/brillig_to_bits/src/main.nr b/test_programs/execution_success/brillig_to_bits/src/main.nr similarity index 100% rename from test_programs/compile_success_empty/brillig_to_bits/src/main.nr rename to test_programs/execution_success/brillig_to_bits/src/main.nr diff --git a/test_programs/compile_success_empty/unconstrained_empty/Nargo.toml b/test_programs/execution_success/unconstrained_empty/Nargo.toml similarity index 100% rename from test_programs/compile_success_empty/unconstrained_empty/Nargo.toml rename to test_programs/execution_success/unconstrained_empty/Nargo.toml diff --git a/test_programs/compile_success_empty/unconstrained_empty/src/main.nr b/test_programs/execution_success/unconstrained_empty/src/main.nr similarity index 100% rename from test_programs/compile_success_empty/unconstrained_empty/src/main.nr rename to test_programs/execution_success/unconstrained_empty/src/main.nr