diff --git a/.noir-sync-commit b/.noir-sync-commit index 7fa9613150e..d3b7e1db860 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -8232bfaf0a88dcba5a6949489b81d78c3413c5bc +ae87d287ab1fae0f999dfd0d1166fbddb927ba97 diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index adc5f73f1ae..a24908fd2e6 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -2539,9 +2539,9 @@ dependencies = [ "rand 0.8.5", "rayon", "serde", - "tempfile", "thiserror", "tracing", + "walkdir", ] [[package]] diff --git a/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml b/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml index d99240c5a24..b57c9356198 100644 --- a/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml +++ b/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml @@ -23,6 +23,7 @@ num-bigint = "0.4" blake2 = "0.10.6" blake3 = "1.5.0" sha2.workspace = true +sha3.workspace = true keccak = "0.1.4" k256 = { version = "0.11.0", features = [ "ecdsa", diff --git a/noir/noir-repo/compiler/fm/src/lib.rs b/noir/noir-repo/compiler/fm/src/lib.rs index 37da29fc982..fad2634bab4 100644 --- a/noir/noir-repo/compiler/fm/src/lib.rs +++ b/noir/noir-repo/compiler/fm/src/lib.rs @@ -100,6 +100,11 @@ impl FileManager { self.id_to_path.get(&file_id).map(|path| path.as_path()) } + pub fn has_file(&self, file_name: &Path) -> bool { + let file_name = self.root.join(file_name); + self.name_to_id(file_name).is_some() + } + // TODO: This should accept a &Path instead of a PathBuf pub fn name_to_id(&self, file_name: PathBuf) -> Option { self.file_map.get_file_id(&PathString::from_path(file_name)) diff --git a/noir/noir-repo/compiler/noirc_errors/src/reporter.rs b/noir/noir-repo/compiler/noirc_errors/src/reporter.rs index 76e308969b4..f029b4e6de8 100644 --- a/noir/noir-repo/compiler/noirc_errors/src/reporter.rs +++ b/noir/noir-repo/compiler/noirc_errors/src/reporter.rs @@ -10,7 +10,7 @@ use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; pub struct CustomDiagnostic { pub message: String, pub secondaries: Vec, - notes: Vec, + pub notes: Vec, pub kind: DiagnosticKind, pub deprecated: bool, pub unnecessary: bool, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 6aa9acaca22..d8dba499a43 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -118,15 +118,15 @@ impl Intrinsic { // These apply a constraint that the input must fit into a specified number of limbs. Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => true, + // These imply a check that the slice is non-empty and should fail otherwise. + Intrinsic::SlicePopBack | Intrinsic::SlicePopFront | Intrinsic::SliceRemove => true, + Intrinsic::ArrayLen | Intrinsic::ArrayAsStrUnchecked | Intrinsic::AsSlice | Intrinsic::SlicePushBack | Intrinsic::SlicePushFront - | Intrinsic::SlicePopBack - | Intrinsic::SlicePopFront | Intrinsic::SliceInsert - | Intrinsic::SliceRemove | Intrinsic::StrAsBytes | Intrinsic::FromField | Intrinsic::AsField diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index dbfa12b7f5e..6d16117d3d8 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -166,6 +166,13 @@ pub(super) fn simplify_call( } } Intrinsic::SlicePopBack => { + let length = dfg.get_numeric_constant(arguments[0]); + if length.map_or(true, |length| length.is_zero()) { + // If the length is zero then we're trying to pop the last element from an empty slice. + // Defer the error to acir_gen. + return SimplifyResult::None; + } + let slice = dfg.get_array_constant(arguments[1]); if let Some((_, typ)) = slice { simplify_slice_pop_back(typ, arguments, dfg, block, call_stack.clone()) @@ -174,6 +181,13 @@ pub(super) fn simplify_call( } } Intrinsic::SlicePopFront => { + let length = dfg.get_numeric_constant(arguments[0]); + if length.map_or(true, |length| length.is_zero()) { + // If the length is zero then we're trying to pop the first element from an empty slice. + // Defer the error to acir_gen. + return SimplifyResult::None; + } + let slice = dfg.get_array_constant(arguments[1]); if let Some((mut slice, typ)) = slice { let element_count = typ.element_size(); @@ -225,6 +239,13 @@ pub(super) fn simplify_call( } } Intrinsic::SliceRemove => { + let length = dfg.get_numeric_constant(arguments[0]); + if length.map_or(true, |length| length.is_zero()) { + // If the length is zero then we're trying to remove an element from an empty slice. + // Defer the error to acir_gen. + return SimplifyResult::None; + } + let slice = dfg.get_array_constant(arguments[1]); let index = dfg.get_numeric_constant(arguments[2]); if let (Some((mut slice, typ)), Some(index)) = (slice, index) { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/array_set.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/array_set.rs index 1cbfca72139..d7be708f518 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/array_set.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/array_set.rs @@ -34,7 +34,7 @@ impl Function { assert_eq!(reachable_blocks.len(), 1, "Expected there to be 1 block remaining in Acir function for array_set optimization"); } - let mut context = Context::new(&self.dfg, matches!(self.runtime(), RuntimeType::Brillig(_))); + let mut context = Context::new(&self.dfg, matches!(self.runtime(), RuntimeType::Brillig)); for block in reachable_blocks.iter() { context.analyze_last_uses(*block); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs index 836c812843e..ef208588718 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -99,7 +99,9 @@ impl<'a> SliceCapacityTracker<'a> { let slice_contents = arguments[argument_index]; if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { - let new_capacity = *contents_capacity - 1; + // We use a saturating sub here as calling `pop_front` or `pop_back` + // on a zero-length slice would otherwise underflow. + let new_capacity = contents_capacity.saturating_sub(1); slice_sizes.insert(result_slice, new_capacity); } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs index 6f3f2fa14b7..4b2d753f072 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs @@ -31,7 +31,7 @@ impl Function { /// The structure of this pass is simple: /// Go through each block and re-insert all instructions. pub(crate) fn remove_bit_shifts(&mut self) { - if matches!(self.runtime(), RuntimeType::Brillig(_)) { + if let RuntimeType::Brillig = self.runtime() { return; } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs index 222ae0aaf29..daae2cb08ce 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs @@ -37,7 +37,7 @@ impl Ssa { impl Function { pub(crate) fn remove_enable_side_effects(&mut self) { - if matches!(self.runtime(), RuntimeType::Brillig(_)) { + if matches!(self.runtime(), RuntimeType::Brillig) { // Brillig functions do not make use of the `EnableSideEffects` instruction so are unaffected by this pass. return; } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs index 57862c699e2..254495bc1d6 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs @@ -38,7 +38,7 @@ impl Ssa { impl Function { pub(crate) fn remove_if_else(&mut self) { // This should match the check in flatten_cfg - if matches!(self.runtime(), RuntimeType::Brillig(_)) { + if let crate::ssa::ir::function::RuntimeType::Brillig = self.runtime() { // skip } else { Context::default().remove_if_else(self); @@ -119,7 +119,9 @@ impl Context { } SizeChange::Dec { old, new } => { let old_capacity = self.get_or_find_capacity(&function.dfg, old); - self.slice_sizes.insert(new, old_capacity - 1); + // We use a saturating sub here as calling `pop_front` or `pop_back` on a zero-length slice + // would otherwise underflow. + self.slice_sizes.insert(new, old_capacity.saturating_sub(1)); } } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs index 3d40c88d704..1768cbddec3 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs @@ -48,7 +48,7 @@ impl Function { self.dfg.replace_result(instruction_id, original_return_id); let is_within_unconstrained = self.dfg.make_constant( - FieldElement::from(matches!(self.runtime(), RuntimeType::Brillig(_))), + FieldElement::from(matches!(self.runtime(), RuntimeType::Brillig)), Type::bool(), ); // Replace all uses of the original return value with the constant diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs index 5fe0d00c2b9..d6ed11ddf0e 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -114,7 +114,7 @@ impl Function { // Loop unrolling in brillig can lead to a code explosion currently. This can // also be true for ACIR, but we have no alternative to unrolling in ACIR. // Brillig also generally prefers smaller code rather than faster code. - if !matches!(self.runtime(), RuntimeType::Brillig(_)) { + if self.runtime() != RuntimeType::Brillig { errors.extend(find_all_loops(self).unroll_each_loop(self)); } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/traits.rs index 61ef6f6276d..723df775b1e 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/traits.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/traits.rs @@ -18,6 +18,7 @@ use super::{Documented, GenericTypeArgs, ItemVisibility}; pub struct NoirTrait { pub name: Ident, pub generics: UnresolvedGenerics, + pub bounds: Vec, pub where_clause: Vec, pub span: Span, pub items: Vec>, @@ -134,7 +135,12 @@ impl Display for NoirTrait { let generics = vecmap(&self.generics, |generic| generic.to_string()); let generics = if generics.is_empty() { "".into() } else { generics.join(", ") }; - writeln!(f, "trait {}{} {{", self.name, generics)?; + write!(f, "trait {}{}", self.name, generics)?; + if !self.bounds.is_empty() { + let bounds = vecmap(&self.bounds, |bound| bound.to_string()).join(" + "); + write!(f, ": {}", bounds)?; + } + writeln!(f, " {{")?; for item in self.items.iter() { let item = item.to_string(); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/expressions.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/expressions.rs index 06bcafc55c9..31a518ca97f 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -26,7 +26,7 @@ use crate::{ HirPrefixExpression, }, stmt::HirStatement, - traits::TraitConstraint, + traits::{ResolvedTraitBound, TraitConstraint}, }, node_interner::{DefinitionKind, ExprId, FuncId, InternedStatementKind, TraitMethodId}, token::Tokens, @@ -743,9 +743,11 @@ impl<'context> Elaborator<'context> { // that implements the trait. let constraint = TraitConstraint { typ: operand_type.clone(), - trait_id: trait_id.trait_id, - trait_generics: TraitGenerics::default(), - span, + trait_bound: ResolvedTraitBound { + trait_id: trait_id.trait_id, + trait_generics: TraitGenerics::default(), + span, + }, }; self.push_trait_constraint(constraint, expr_id); self.type_check_operator_method(expr_id, trait_id, operand_type, span); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs index a9173621fc7..5067ac05c44 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs @@ -3,7 +3,7 @@ use std::{ rc::Rc, }; -use crate::{ast::ItemVisibility, StructField}; +use crate::{ast::ItemVisibility, hir_def::traits::ResolvedTraitBound, StructField, TypeBindings}; use crate::{ ast::{ BlockExpression, FunctionKind, GenericTypeArgs, Ident, NoirFunction, NoirStruct, Param, @@ -54,6 +54,7 @@ mod unquote; use fm::FileId; use iter_extended::vecmap; use noirc_errors::{Location, Span}; +use types::bind_ordered_generics; use self::traits::check_trait_impl_method_matches_declaration; @@ -433,7 +434,8 @@ impl<'context> Elaborator<'context> { // Now remove all the `where` clause constraints we added for constraint in &func_meta.trait_constraints { - self.interner.remove_assumed_trait_implementations_for_trait(constraint.trait_id); + self.interner + .remove_assumed_trait_implementations_for_trait(constraint.trait_bound.trait_id); } let func_scope_tree = self.scopes.end_function(); @@ -479,9 +481,9 @@ impl<'context> Elaborator<'context> { self.verify_trait_constraint( &constraint.typ, - constraint.trait_id, - &constraint.trait_generics.ordered, - &constraint.trait_generics.named, + constraint.trait_bound.trait_id, + &constraint.trait_bound.trait_generics.ordered, + &constraint.trait_bound.trait_generics.named, expr_id, span, ); @@ -510,7 +512,8 @@ impl<'context> Elaborator<'context> { let generic_type = Type::NamedGeneric(new_generic, Rc::new(name)); let trait_bound = TraitBound { trait_path, trait_id: None, trait_generics }; - if let Some(new_constraint) = self.resolve_trait_bound(&trait_bound, generic_type.clone()) { + if let Some(trait_bound) = self.resolve_trait_bound(&trait_bound) { + let new_constraint = TraitConstraint { typ: generic_type.clone(), trait_bound }; trait_constraints.push(new_constraint); } @@ -668,14 +671,11 @@ impl<'context> Elaborator<'context> { constraint: &UnresolvedTraitConstraint, ) -> Option { let typ = self.resolve_type(constraint.typ.clone()); - self.resolve_trait_bound(&constraint.trait_bound, typ) + let trait_bound = self.resolve_trait_bound(&constraint.trait_bound)?; + Some(TraitConstraint { typ, trait_bound }) } - pub fn resolve_trait_bound( - &mut self, - bound: &TraitBound, - typ: Type, - ) -> Option { + pub fn resolve_trait_bound(&mut self, bound: &TraitBound) -> Option { let the_trait = self.lookup_trait_or_error(bound.trait_path.clone())?; let trait_id = the_trait.id; let span = bound.trait_path.span; @@ -683,7 +683,7 @@ impl<'context> Elaborator<'context> { let (ordered, named) = self.resolve_type_args(bound.trait_generics.clone(), trait_id, span); let trait_generics = TraitGenerics { ordered, named }; - Some(TraitConstraint { typ, trait_id, trait_generics, span }) + Some(ResolvedTraitBound { trait_id, trait_generics, span }) } /// Extract metadata from a NoirFunction @@ -760,7 +760,6 @@ impl<'context> Elaborator<'context> { DefinitionKind::Local(None), &mut parameter_idents, true, // warn_if_unused - None, ); parameters.push((pattern, typ.clone(), visibility)); @@ -942,21 +941,52 @@ impl<'context> Elaborator<'context> { fn add_trait_constraints_to_scope(&mut self, func_meta: &FuncMeta) { for constraint in &func_meta.trait_constraints { - let object = constraint.typ.clone(); - let trait_id = constraint.trait_id; - let generics = constraint.trait_generics.clone(); - - if !self.interner.add_assumed_trait_implementation(object, trait_id, generics) { - if let Some(the_trait) = self.interner.try_get_trait(trait_id) { - let trait_name = the_trait.name.to_string(); - let typ = constraint.typ.clone(); - let span = func_meta.location.span; - self.push_err(TypeCheckError::UnneededTraitConstraint { - trait_name, - typ, - span, - }); + self.add_trait_bound_to_scope( + func_meta, + &constraint.typ, + &constraint.trait_bound, + constraint.trait_bound.trait_id, + ); + } + } + + fn add_trait_bound_to_scope( + &mut self, + func_meta: &FuncMeta, + object: &Type, + trait_bound: &ResolvedTraitBound, + starting_trait_id: TraitId, + ) { + let trait_id = trait_bound.trait_id; + let generics = trait_bound.trait_generics.clone(); + + if !self.interner.add_assumed_trait_implementation(object.clone(), trait_id, generics) { + if let Some(the_trait) = self.interner.try_get_trait(trait_id) { + let trait_name = the_trait.name.to_string(); + let typ = object.clone(); + let span = func_meta.location.span; + self.push_err(TypeCheckError::UnneededTraitConstraint { trait_name, typ, span }); + } + } + + // Also add assumed implementations for the parent traits, if any + if let Some(trait_bounds) = + self.interner.try_get_trait(trait_id).map(|the_trait| the_trait.trait_bounds.clone()) + { + for parent_trait_bound in trait_bounds { + // Avoid looping forever in case there are cycles + if parent_trait_bound.trait_id == starting_trait_id { + continue; } + + let parent_trait_bound = + self.instantiate_parent_trait_bound(trait_bound, &parent_trait_bound); + self.add_trait_bound_to_scope( + func_meta, + object, + &parent_trait_bound, + starting_trait_id, + ); } } } @@ -972,6 +1002,8 @@ impl<'context> Elaborator<'context> { self.file = trait_impl.file_id; self.local_module = trait_impl.module_id; + self.check_parent_traits_are_implemented(&trait_impl); + self.generics = trait_impl.resolved_generics; self.current_trait_impl = trait_impl.impl_id; @@ -988,6 +1020,73 @@ impl<'context> Elaborator<'context> { self.generics.clear(); } + fn check_parent_traits_are_implemented(&mut self, trait_impl: &UnresolvedTraitImpl) { + let Some(trait_id) = trait_impl.trait_id else { + return; + }; + + let Some(object_type) = &trait_impl.resolved_object_type else { + return; + }; + + let Some(the_trait) = self.interner.try_get_trait(trait_id) else { + return; + }; + + if the_trait.trait_bounds.is_empty() { + return; + } + + let impl_trait = the_trait.name.to_string(); + let the_trait_file = the_trait.location.file; + + let mut bindings = TypeBindings::new(); + bind_ordered_generics( + &the_trait.generics, + &trait_impl.resolved_trait_generics, + &mut bindings, + ); + + // Note: we only check if the immediate parents are implemented, we don't check recursively. + // Why? If a parent isn't implemented, we get an error. If a parent is implemented, we'll + // do the same check for the parent, so this trait's parents parents will be checked, so the + // recursion is guaranteed. + for parent_trait_bound in the_trait.trait_bounds.clone() { + let Some(parent_trait) = self.interner.try_get_trait(parent_trait_bound.trait_id) + else { + continue; + }; + + let parent_trait_bound = ResolvedTraitBound { + trait_generics: parent_trait_bound + .trait_generics + .map(|typ| typ.substitute(&bindings)), + ..parent_trait_bound + }; + + if self + .interner + .try_lookup_trait_implementation( + object_type, + parent_trait_bound.trait_id, + &parent_trait_bound.trait_generics.ordered, + &parent_trait_bound.trait_generics.named, + ) + .is_err() + { + let missing_trait = + format!("{}{}", parent_trait.name, parent_trait_bound.trait_generics); + self.push_err(ResolverError::TraitNotImplemented { + impl_trait: impl_trait.clone(), + missing_trait, + type_missing_trait: trait_impl.object_type.to_string(), + span: trait_impl.object_type.span, + missing_trait_location: Location::new(parent_trait_bound.span, the_trait_file), + }); + } + } + } + fn collect_impls( &mut self, module: LocalModuleId, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/patterns.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/patterns.rs index 0f6cb78fae7..d55011f98a1 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -37,7 +37,6 @@ impl<'context> Elaborator<'context> { None, &mut Vec::new(), warn_if_unused, - None, ) } @@ -50,7 +49,6 @@ impl<'context> Elaborator<'context> { definition_kind: DefinitionKind, created_ids: &mut Vec, warn_if_unused: bool, - global_id: Option, ) -> HirPattern { self.elaborate_pattern_mut( pattern, @@ -59,7 +57,6 @@ impl<'context> Elaborator<'context> { None, created_ids, warn_if_unused, - global_id, ) } @@ -72,7 +69,6 @@ impl<'context> Elaborator<'context> { mutable: Option, new_definitions: &mut Vec, warn_if_unused: bool, - global_id: Option, ) -> HirPattern { match pattern { Pattern::Identifier(name) => { @@ -82,7 +78,7 @@ impl<'context> Elaborator<'context> { (Some(_), DefinitionKind::Local(_)) => DefinitionKind::Local(None), (_, other) => other, }; - let ident = if let Some(global_id) = global_id { + let ident = if let DefinitionKind::Global(global_id) = definition { // Globals don't need to be added to scope, they're already in the def_maps let id = self.interner.get_global(global_id).definition_id; let location = Location::new(name.span(), self.file); @@ -112,7 +108,6 @@ impl<'context> Elaborator<'context> { Some(span), new_definitions, warn_if_unused, - global_id, ); let location = Location::new(span, self.file); HirPattern::Mutable(Box::new(pattern), location) @@ -144,7 +139,6 @@ impl<'context> Elaborator<'context> { mutable, new_definitions, warn_if_unused, - global_id, ) }); let location = Location::new(span, self.file); @@ -168,7 +162,6 @@ impl<'context> Elaborator<'context> { mutable, new_definitions, warn_if_unused, - global_id, ) } } @@ -283,7 +276,6 @@ impl<'context> Elaborator<'context> { mutable, new_definitions, true, // warn_if_unused - None, ); if unseen_fields.contains(&field) { @@ -329,8 +321,8 @@ impl<'context> Elaborator<'context> { warn_if_unused: bool, definition: DefinitionKind, ) -> HirIdent { - if definition.is_global() { - return self.add_global_variable_decl(name, definition); + if let DefinitionKind::Global(global_id) = definition { + return self.add_global_variable_decl(name, global_id); } let location = Location::new(name.span(), self.file); @@ -375,47 +367,19 @@ impl<'context> Elaborator<'context> { } } - pub fn add_global_variable_decl( - &mut self, - name: Ident, - definition: DefinitionKind, - ) -> HirIdent { - let comptime = self.in_comptime_context(); + pub fn add_global_variable_decl(&mut self, name: Ident, global_id: GlobalId) -> HirIdent { let scope = self.scopes.get_mut_scope(); - - // This check is necessary to maintain the same definition ids in the interner. Currently, each function uses a new resolver that has its own ScopeForest and thus global scope. - // We must first check whether an existing definition ID has been inserted as otherwise there will be multiple definitions for the same global statement. - // This leads to an error in evaluation where the wrong definition ID is selected when evaluating a statement using the global. The check below prevents this error. - let mut global_id = None; - let global = self.interner.get_all_globals(); - for global_info in global { - if global_info.local_id == self.local_module && global_info.ident == name { - global_id = Some(global_info.id); - } - } - - let (ident, resolver_meta) = if let Some(id) = global_id { - let global = self.interner.get_global(id); - let hir_ident = HirIdent::non_trait_method(global.definition_id, global.location); - let ident = hir_ident.clone(); - let resolver_meta = ResolverMeta { num_times_used: 0, ident, warn_if_unused: true }; - (hir_ident, resolver_meta) - } else { - let location = Location::new(name.span(), self.file); - let name = name.0.contents.clone(); - let id = self.interner.push_definition(name, false, comptime, definition, location); - let ident = HirIdent::non_trait_method(id, location); - let resolver_meta = - ResolverMeta { num_times_used: 0, ident: ident.clone(), warn_if_unused: true }; - (ident, resolver_meta) - }; + let global = self.interner.get_global(global_id); + let ident = HirIdent::non_trait_method(global.definition_id, global.location); + let resolver_meta = + ResolverMeta { num_times_used: 0, ident: ident.clone(), warn_if_unused: true }; let old_global_value = scope.add_key_value(name.0.contents.clone(), resolver_meta); if let Some(old_global_value) = old_global_value { self.push_err(ResolverError::DuplicateDefinition { - name: name.0.contents.clone(), - first_span: old_global_value.ident.location.span, second_span: name.span(), + name: name.0.contents, + first_span: old_global_value.ident.location.span, }); } ident @@ -655,7 +619,7 @@ impl<'context> Elaborator<'context> { if let ImplKind::TraitMethod(mut method) = ident.impl_kind { method.constraint.apply_bindings(&bindings); if method.assumed { - let trait_generics = method.constraint.trait_generics.clone(); + let trait_generics = method.constraint.trait_bound.trait_generics.clone(); let object_type = method.constraint.typ; let trait_impl = TraitImplKind::Assumed { object_type, trait_generics }; self.interner.select_impl_for_expression(expr_id, trait_impl); @@ -748,7 +712,7 @@ impl<'context> Elaborator<'context> { HirMethodReference::TraitMethodId(method_id, generics) => { let mut constraint = self.interner.get_trait(method_id.trait_id).as_constraint(span); - constraint.trait_generics = generics; + constraint.trait_bound.trait_generics = generics; ImplKind::TraitMethod(TraitMethod { method_id, constraint, assumed: false }) } }; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/statements.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/statements.rs index 0be71e39587..238160e5aa4 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/statements.rs @@ -110,7 +110,6 @@ impl<'context> Elaborator<'context> { definition, &mut Vec::new(), warn_if_unused, - global_id, ); let attributes = let_stmt.attributes; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/trait_impls.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/trait_impls.rs index 858cfa5cdd6..20f048bed05 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/trait_impls.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/trait_impls.rs @@ -167,12 +167,14 @@ impl<'context> Elaborator<'context> { let mut substituted_method_ids = HashSet::default(); for method_constraint in method.trait_constraints.iter() { let substituted_constraint_type = method_constraint.typ.substitute(&bindings); - let substituted_trait_generics = - method_constraint.trait_generics.map(|generic| generic.substitute(&bindings)); + let substituted_trait_generics = method_constraint + .trait_bound + .trait_generics + .map(|generic| generic.substitute(&bindings)); substituted_method_ids.insert(( substituted_constraint_type, - method_constraint.trait_id, + method_constraint.trait_bound.trait_id, substituted_trait_generics, )); } @@ -180,7 +182,8 @@ impl<'context> Elaborator<'context> { for override_trait_constraint in override_meta.trait_constraints.clone() { let override_constraint_is_from_impl = trait_impl_where_clause.iter().any(|impl_constraint| { - impl_constraint.trait_id == override_trait_constraint.trait_id + impl_constraint.trait_bound.trait_id + == override_trait_constraint.trait_bound.trait_id }); if override_constraint_is_from_impl { continue; @@ -188,15 +191,16 @@ impl<'context> Elaborator<'context> { if !substituted_method_ids.contains(&( override_trait_constraint.typ.clone(), - override_trait_constraint.trait_id, - override_trait_constraint.trait_generics.clone(), + override_trait_constraint.trait_bound.trait_id, + override_trait_constraint.trait_bound.trait_generics.clone(), )) { - let the_trait = self.interner.get_trait(override_trait_constraint.trait_id); + let the_trait = + self.interner.get_trait(override_trait_constraint.trait_bound.trait_id); self.push_err(DefCollectorErrorKind::ImplIsStricterThanTrait { constraint_typ: override_trait_constraint.typ, constraint_name: the_trait.name.0.contents.clone(), - constraint_generics: override_trait_constraint.trait_generics, - constraint_span: override_trait_constraint.span, + constraint_generics: override_trait_constraint.trait_bound.trait_generics, + constraint_span: override_trait_constraint.trait_bound.span, trait_method_name: method.name.0.contents.clone(), trait_method_span: method.location.span, }); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/traits.rs index b4042bd3e31..e877682972c 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/traits.rs @@ -10,8 +10,11 @@ use crate::{ UnresolvedTraitConstraint, UnresolvedType, }, hir::{def_collector::dc_crate::UnresolvedTrait, type_check::TypeCheckError}, - hir_def::{function::Parameters, traits::TraitFunction}, - node_interner::{FuncId, NodeInterner, ReferenceId, TraitId}, + hir_def::{ + function::Parameters, + traits::{ResolvedTraitBound, TraitFunction}, + }, + node_interner::{DependencyId, FuncId, NodeInterner, ReferenceId, TraitId}, ResolvedGeneric, Type, TypeBindings, }; @@ -34,10 +37,17 @@ impl<'context> Elaborator<'context> { this.generics.push(associated_type.clone()); } + let resolved_trait_bounds = this.resolve_trait_bounds(unresolved_trait); + for bound in &resolved_trait_bounds { + this.interner + .add_trait_dependency(DependencyId::Trait(bound.trait_id), *trait_id); + } + let methods = this.resolve_trait_methods(*trait_id, unresolved_trait); this.interner.update_trait(*trait_id, |trait_def| { trait_def.set_methods(methods); + trait_def.set_trait_bounds(resolved_trait_bounds); }); }); @@ -53,6 +63,14 @@ impl<'context> Elaborator<'context> { self.current_trait = None; } + fn resolve_trait_bounds( + &mut self, + unresolved_trait: &UnresolvedTrait, + ) -> Vec { + let bounds = &unresolved_trait.trait_def.bounds; + bounds.iter().filter_map(|bound| self.resolve_trait_bound(bound)).collect() + } + fn resolve_trait_methods( &mut self, trait_id: TraitId, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs index 82d14743428..8ffbd15bdab 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs @@ -28,7 +28,7 @@ use crate::{ }, function::{FuncMeta, Parameters}, stmt::HirStatement, - traits::{NamedType, TraitConstraint}, + traits::{NamedType, ResolvedTraitBound, Trait, TraitConstraint}, }, node_interner::{ DefinitionKind, DependencyId, ExprId, GlobalId, ImplSearchErrorKind, NodeInterner, TraitId, @@ -596,7 +596,7 @@ impl<'context> Elaborator<'context> { continue; } - let the_trait = self.interner.get_trait(constraint.trait_id); + let the_trait = self.interner.get_trait(constraint.trait_bound.trait_id); if let Some(method) = the_trait.find_method(path.last_name()) { return Some(TraitPathResolution { method: TraitMethod { method_id: method, constraint, assumed: true }, @@ -1376,15 +1376,16 @@ impl<'context> Elaborator<'context> { for constraint in &func_meta.trait_constraints { if *object_type == constraint.typ { - if let Some(the_trait) = self.interner.try_get_trait(constraint.trait_id) { - for (method_index, method) in the_trait.methods.iter().enumerate() { - if method.name.0.contents == method_name { - let trait_method = - TraitMethodId { trait_id: constraint.trait_id, method_index }; - - let generics = constraint.trait_generics.clone(); - return Some(HirMethodReference::TraitMethodId(trait_method, generics)); - } + if let Some(the_trait) = + self.interner.try_get_trait(constraint.trait_bound.trait_id) + { + if let Some(method) = self.lookup_method_in_trait( + the_trait, + method_name, + &constraint.trait_bound, + the_trait.id, + ) { + return Some(method); } } } @@ -1399,6 +1400,44 @@ impl<'context> Elaborator<'context> { None } + fn lookup_method_in_trait( + &self, + the_trait: &Trait, + method_name: &str, + trait_bound: &ResolvedTraitBound, + starting_trait_id: TraitId, + ) -> Option { + if let Some(trait_method) = the_trait.find_method(method_name) { + return Some(HirMethodReference::TraitMethodId( + trait_method, + trait_bound.trait_generics.clone(), + )); + } + + // Search in the parent traits, if any + for parent_trait_bound in &the_trait.trait_bounds { + if let Some(the_trait) = self.interner.try_get_trait(parent_trait_bound.trait_id) { + // Avoid looping forever in case there are cycles + if the_trait.id == starting_trait_id { + continue; + } + + let parent_trait_bound = + self.instantiate_parent_trait_bound(trait_bound, parent_trait_bound); + if let Some(method) = self.lookup_method_in_trait( + the_trait, + method_name, + &parent_trait_bound, + starting_trait_id, + ) { + return Some(method); + } + } + } + + None + } + pub(super) fn type_check_call( &mut self, call: &HirCallExpression, @@ -1801,55 +1840,86 @@ impl<'context> Elaborator<'context> { } pub fn bind_generics_from_trait_constraint( - &mut self, + &self, constraint: &TraitConstraint, assumed: bool, bindings: &mut TypeBindings, ) { - let the_trait = self.interner.get_trait(constraint.trait_id); - assert_eq!(the_trait.generics.len(), constraint.trait_generics.ordered.len()); - - for (param, arg) in the_trait.generics.iter().zip(&constraint.trait_generics.ordered) { - // Avoid binding t = t - if !arg.occurs(param.type_var.id()) { - bindings.insert( - param.type_var.id(), - (param.type_var.clone(), param.kind(), arg.clone()), - ); - } - } - - let mut associated_types = the_trait.associated_types.clone(); - assert_eq!(associated_types.len(), constraint.trait_generics.named.len()); - - for arg in &constraint.trait_generics.named { - let i = associated_types - .iter() - .position(|typ| *typ.name == arg.name.0.contents) - .unwrap_or_else(|| { - unreachable!("Expected to find associated type named {}", arg.name) - }); - - let param = associated_types.swap_remove(i); - - // Avoid binding t = t - if !arg.typ.occurs(param.type_var.id()) { - bindings.insert( - param.type_var.id(), - (param.type_var.clone(), param.kind(), arg.typ.clone()), - ); - } - } + self.bind_generics_from_trait_bound(&constraint.trait_bound, bindings); // If the trait impl is already assumed to exist we should add any type bindings for `Self`. // Otherwise `self` will be replaced with a fresh type variable, which will require the user // to specify a redundant type annotation. if assumed { + let the_trait = self.interner.get_trait(constraint.trait_bound.trait_id); let self_type = the_trait.self_type_typevar.clone(); let kind = the_trait.self_type_typevar.kind(); bindings.insert(self_type.id(), (self_type, kind, constraint.typ.clone())); } } + + pub fn bind_generics_from_trait_bound( + &self, + trait_bound: &ResolvedTraitBound, + bindings: &mut TypeBindings, + ) { + let the_trait = self.interner.get_trait(trait_bound.trait_id); + + bind_ordered_generics(&the_trait.generics, &trait_bound.trait_generics.ordered, bindings); + + let associated_types = the_trait.associated_types.clone(); + bind_named_generics(associated_types, &trait_bound.trait_generics.named, bindings); + } + + pub fn instantiate_parent_trait_bound( + &self, + trait_bound: &ResolvedTraitBound, + parent_trait_bound: &ResolvedTraitBound, + ) -> ResolvedTraitBound { + let mut bindings = TypeBindings::new(); + self.bind_generics_from_trait_bound(trait_bound, &mut bindings); + ResolvedTraitBound { + trait_generics: parent_trait_bound.trait_generics.map(|typ| typ.substitute(&bindings)), + ..*parent_trait_bound + } + } +} + +pub(crate) fn bind_ordered_generics( + params: &[ResolvedGeneric], + args: &[Type], + bindings: &mut TypeBindings, +) { + assert_eq!(params.len(), args.len()); + + for (param, arg) in params.iter().zip(args) { + bind_generic(param, arg, bindings); + } +} + +pub(crate) fn bind_named_generics( + mut params: Vec, + args: &[NamedType], + bindings: &mut TypeBindings, +) { + assert_eq!(params.len(), args.len()); + + for arg in args { + let i = params + .iter() + .position(|typ| *typ.name == arg.name.0.contents) + .unwrap_or_else(|| unreachable!("Expected to find associated type named {}", arg.name)); + + let param = params.swap_remove(i); + bind_generic(¶m, &arg.typ, bindings); + } +} + +fn bind_generic(param: &ResolvedGeneric, arg: &Type, bindings: &mut TypeBindings) { + // Avoid binding t = t + if !arg.occurs(param.type_var.id()) { + bindings.insert(param.type_var.id(), (param.type_var.clone(), param.kind(), arg.clone())); + } } pub fn try_eval_array_length_id( diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/display.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/display.rs index fa45c41f8ec..60661211a09 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/display.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/display.rs @@ -509,8 +509,11 @@ impl<'token, 'interner> Display for TokenPrinter<'token, 'interner> { } fn display_trait_constraint(interner: &NodeInterner, trait_constraint: &TraitConstraint) -> String { - let trait_ = interner.get_trait(trait_constraint.trait_id); - format!("{}: {}{}", trait_constraint.typ, trait_.name, trait_constraint.trait_generics) + let trait_ = interner.get_trait(trait_constraint.trait_bound.trait_id); + format!( + "{}: {}{}", + trait_constraint.typ, trait_.name, trait_constraint.trait_bound.trait_generics + ) } // Returns a new Expression where all Interned and Resolved expressions have been turned into non-interned ExpressionKind. diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index b34c7d54b00..15ceffa3e97 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -751,7 +751,7 @@ fn quoted_as_trait_constraint( )?; let bound = interpreter .elaborate_in_function(interpreter.current_function, |elaborator| { - elaborator.resolve_trait_bound(&trait_bound, Type::Unit) + elaborator.resolve_trait_bound(&trait_bound) }) .ok_or(InterpreterError::FailedToResolveTraitBound { trait_bound, location })?; @@ -2465,7 +2465,6 @@ fn function_def_set_parameters( DefinitionKind::Local(None), &mut parameter_idents, true, // warn_if_unused - None, ) }); @@ -2753,7 +2752,7 @@ fn trait_def_as_trait_constraint( let trait_id = get_trait_def(argument)?; let constraint = interner.get_trait(trait_id).as_constraint(location.span); - Ok(Value::TraitConstraint(trait_id, constraint.trait_generics)) + Ok(Value::TraitConstraint(trait_id, constraint.trait_bound.trait_generics)) } /// Creates a value that holds an `Option`. diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs index a6eb1864d13..4f9907d6a16 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -1,6 +1,6 @@ use acvm::FieldElement; pub use noirc_errors::Span; -use noirc_errors::{CustomDiagnostic as Diagnostic, FileDiagnostic}; +use noirc_errors::{CustomDiagnostic as Diagnostic, FileDiagnostic, Location}; use thiserror::Error; use crate::{ @@ -150,6 +150,14 @@ pub enum ResolverError { AttributeFunctionIsNotAPath { function: String, span: Span }, #[error("Attribute function `{name}` is not in scope")] AttributeFunctionNotInScope { name: String, span: Span }, + #[error("The trait `{missing_trait}` is not implemented for `{type_missing_trait}")] + TraitNotImplemented { + impl_trait: String, + missing_trait: String, + type_missing_trait: String, + span: Span, + missing_trait_location: Location, + }, } impl ResolverError { @@ -579,6 +587,14 @@ impl<'a> From<&'a ResolverError> for Diagnostic { *span, ) }, + ResolverError::TraitNotImplemented { impl_trait, missing_trait: the_trait, type_missing_trait: typ, span, 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}") + , *span); + diagnostic.add_secondary_with_file(format!("required by this bound in `{impl_trait}"), missing_trait_location.span, missing_trait_location.file); + diagnostic + }, } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs index d8dae1f6549..99de6bca434 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -506,8 +506,8 @@ impl NoMatchingImplFoundError { let constraints = failing_constraints .into_iter() .map(|constraint| { - let r#trait = interner.try_get_trait(constraint.trait_id)?; - let name = format!("{}{}", r#trait.name, constraint.trait_generics); + let r#trait = interner.try_get_trait(constraint.trait_bound.trait_id)?; + let name = format!("{}{}", r#trait.name, constraint.trait_bound.trait_generics); Some((constraint.typ, name)) }) .collect::>>()?; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/generics.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/generics.rs index 86fc2d25d4e..370223f1f11 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/generics.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/generics.rs @@ -133,6 +133,10 @@ impl TraitGenerics { vecmap(&self.named, |named| NamedType { name: named.name.clone(), typ: f(&named.typ) }); TraitGenerics { ordered, named } } + + pub fn is_empty(&self) -> bool { + self.ordered.is_empty() && self.named.is_empty() + } } impl std::fmt::Display for TraitGenerics { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs index 71e0256a7e8..5d3fe632a74 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs @@ -11,7 +11,7 @@ use crate::token::Tokens; use crate::Shared; use super::stmt::HirPattern; -use super::traits::TraitConstraint; +use super::traits::{ResolvedTraitBound, TraitConstraint}; use super::types::{StructType, Type}; /// A HirExpression is the result of an Expression in the AST undergoing @@ -250,9 +250,11 @@ impl HirMethodCallExpression { let id = interner.trait_method_id(method_id); let constraint = TraitConstraint { typ: object_type, - trait_id: method_id.trait_id, - trait_generics, - span: location.span, + trait_bound: ResolvedTraitBound { + trait_id: method_id.trait_id, + trait_generics, + span: location.span, + }, }; (id, ImplKind::TraitMethod(TraitMethod { method_id, constraint, assumed: false })) } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/traits.rs index 3859db26e39..534805c2dad 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/traits.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/traits.rs @@ -72,6 +72,9 @@ pub struct Trait { /// match the definition in the trait, we bind this TypeVariable to whatever /// the correct Self type is for that particular impl block. pub self_type_typevar: TypeVariable, + + /// The resolved trait bounds (for example in `trait Foo: Bar + Baz`, this would be `Bar + Baz`) + pub trait_bounds: Vec, } #[derive(Debug)] @@ -101,15 +104,25 @@ pub struct TraitImpl { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitConstraint { pub typ: Type, - pub trait_id: TraitId, - pub trait_generics: TraitGenerics, - pub span: Span, + pub trait_bound: ResolvedTraitBound, } impl TraitConstraint { pub fn apply_bindings(&mut self, type_bindings: &TypeBindings) { self.typ = self.typ.substitute(type_bindings); + self.trait_bound.apply_bindings(type_bindings); + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ResolvedTraitBound { + pub trait_id: TraitId, + pub trait_generics: TraitGenerics, + pub span: Span, +} +impl ResolvedTraitBound { + pub fn apply_bindings(&mut self, type_bindings: &TypeBindings) { for typ in &mut self.trait_generics.ordered { *typ = typ.substitute(type_bindings); } @@ -137,6 +150,10 @@ impl Trait { self.methods = methods; } + pub fn set_trait_bounds(&mut self, trait_bounds: Vec) { + self.trait_bounds = trait_bounds; + } + pub fn find_method(&self, name: &str) -> Option { for (idx, method) in self.methods.iter().enumerate() { if &method.name == name { @@ -169,9 +186,11 @@ impl Trait { TraitConstraint { typ: Type::TypeVariable(self.self_type_typevar.clone()), - trait_generics: TraitGenerics { ordered, named }, - trait_id: self.id, - span, + trait_bound: ResolvedTraitBound { + trait_generics: TraitGenerics { ordered, named }, + trait_id: self.id, + span, + }, } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs index b80c37c2ce4..ca7e0c6aa59 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs @@ -24,6 +24,7 @@ use crate::hir::def_map::DefMaps; use crate::hir::def_map::{LocalModuleId, ModuleDefId, ModuleId}; use crate::hir::type_check::generics::TraitGenerics; use crate::hir_def::traits::NamedType; +use crate::hir_def::traits::ResolvedTraitBound; use crate::usage_tracker::UnusedItem; use crate::usage_tracker::UsageTracker; use crate::QuotedType; @@ -291,6 +292,7 @@ pub enum DependencyId { Global(GlobalId), Function(FuncId), Alias(TypeAliasId), + Trait(TraitId), Variable(Location), } @@ -732,6 +734,7 @@ impl NodeInterner { methods: Vec::new(), method_ids: unresolved_trait.method_ids.clone(), associated_types, + trait_bounds: Vec::new(), }; self.traits.insert(type_id, new_trait); @@ -1531,9 +1534,11 @@ impl NodeInterner { let named = trait_associated_types.to_vec(); TraitConstraint { typ: object_type.clone(), - trait_id, - trait_generics: TraitGenerics { ordered, named }, - span: Span::default(), + trait_bound: ResolvedTraitBound { + trait_id, + trait_generics: TraitGenerics { ordered, named }, + span: Span::default(), + }, } }; @@ -1613,9 +1618,11 @@ impl NodeInterner { let constraint = TraitConstraint { typ: existing_object_type, - trait_id, - trait_generics, - span: Span::default(), + trait_bound: ResolvedTraitBound { + trait_id, + trait_generics, + span: Span::default(), + }, }; matching_impls.push((impl_kind.clone(), fresh_bindings, constraint)); } @@ -1635,8 +1642,8 @@ impl NodeInterner { Err(ImplSearchErrorKind::Nested(errors)) } else { let impls = vecmap(matching_impls, |(_, _, constraint)| { - let name = &self.get_trait(constraint.trait_id).name; - format!("{}: {name}{}", constraint.typ, constraint.trait_generics) + let name = &self.get_trait(constraint.trait_bound.trait_id).name; + format!("{}: {name}{}", constraint.typ, constraint.trait_bound.trait_generics) }); Err(ImplSearchErrorKind::MultipleMatching(impls)) } @@ -1658,20 +1665,22 @@ impl NodeInterner { let constraint_type = constraint.typ.force_substitute(instantiation_bindings).substitute(type_bindings); - let trait_generics = vecmap(&constraint.trait_generics.ordered, |generic| { - generic.force_substitute(instantiation_bindings).substitute(type_bindings) - }); + let trait_generics = + vecmap(&constraint.trait_bound.trait_generics.ordered, |generic| { + generic.force_substitute(instantiation_bindings).substitute(type_bindings) + }); - let trait_associated_types = vecmap(&constraint.trait_generics.named, |generic| { - let typ = generic.typ.force_substitute(instantiation_bindings); - NamedType { name: generic.name.clone(), typ: typ.substitute(type_bindings) } - }); + let trait_associated_types = + vecmap(&constraint.trait_bound.trait_generics.named, |generic| { + let typ = generic.typ.force_substitute(instantiation_bindings); + NamedType { name: generic.name.clone(), typ: typ.substitute(type_bindings) } + }); // We can ignore any associated types on the constraint since those should not affect // which impl we choose. self.lookup_trait_implementation_helper( &constraint_type, - constraint.trait_id, + constraint.trait_bound.trait_id, &trait_generics, &trait_associated_types, // Use a fresh set of type bindings here since the constraint_type originates from @@ -2016,6 +2025,10 @@ impl NodeInterner { self.add_dependency(dependent, DependencyId::Alias(dependency)); } + pub fn add_trait_dependency(&mut self, dependent: DependencyId, dependency: TraitId) { + self.add_dependency(dependent, DependencyId::Trait(dependency)); + } + pub fn add_dependency(&mut self, dependent: DependencyId, dependency: DependencyId) { let dependent_index = self.get_or_insert_dependency(dependent); let dependency_index = self.get_or_insert_dependency(dependency); @@ -2071,6 +2084,11 @@ impl NodeInterner { push_error(alias.name.to_string(), &scc, i, alias.location); break; } + DependencyId::Trait(trait_id) => { + let the_trait = self.get_trait(trait_id); + push_error(the_trait.name.to_string(), &scc, i, the_trait.location); + break; + } // Mutually recursive functions are allowed DependencyId::Function(_) => (), // Local variables should never be in a dependency cycle, scoping rules @@ -2099,6 +2117,7 @@ impl NodeInterner { DependencyId::Global(id) => { Cow::Borrowed(self.get_global(id).ident.0.contents.as_ref()) } + DependencyId::Trait(id) => Cow::Owned(self.get_trait(id).name.to_string()), DependencyId::Variable(loc) => { unreachable!("Variable used at location {loc:?} caught in a dependency cycle") } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/traits.rs index 3bae152e75f..fead6a34c82 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -11,7 +11,7 @@ use super::parse_many::without_separator; use super::Parser; impl<'a> Parser<'a> { - /// Trait = 'trait' identifier Generics WhereClause TraitBody + /// Trait = 'trait' identifier Generics ( ':' TraitBounds )? WhereClause TraitBody pub(crate) fn parse_trait( &mut self, attributes: Vec<(Attribute, Span)>, @@ -26,12 +26,14 @@ impl<'a> Parser<'a> { }; let generics = self.parse_generics(); + let bounds = if self.eat_colon() { self.parse_trait_bounds() } else { Vec::new() }; let where_clause = self.parse_where_clause(); let items = self.parse_trait_body(); NoirTrait { name, generics, + bounds, where_clause, span: self.span_since(start_span), items, @@ -180,6 +182,7 @@ fn empty_trait( NoirTrait { name: Ident::default(), generics: Vec::new(), + bounds: Vec::new(), where_clause: Vec::new(), span, items: Vec::new(), @@ -292,4 +295,16 @@ mod tests { }; assert!(body.is_some()); } + + #[test] + fn parse_trait_inheirtance() { + let src = "trait Foo: Bar + Baz {}"; + let noir_trait = parse_trait_no_errors(src); + assert_eq!(noir_trait.bounds.len(), 2); + + assert_eq!(noir_trait.bounds[0].to_string(), "Bar"); + assert_eq!(noir_trait.bounds[1].to_string(), "Baz"); + + assert_eq!(noir_trait.to_string(), "trait Foo: Bar + Baz {\n}"); + } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs index 851f28d868d..17acd17dcc9 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs @@ -4,6 +4,7 @@ mod bound_checks; mod imports; mod name_shadowing; mod references; +mod traits; mod turbofish; mod unused_items; mod visibility; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests/traits.rs new file mode 100644 index 00000000000..ee84cc0e890 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests/traits.rs @@ -0,0 +1,150 @@ +use crate::hir::def_collector::dc_crate::CompilationError; +use crate::hir::resolution::errors::ResolverError; +use crate::tests::get_program_errors; + +use super::assert_no_errors; + +#[test] +fn trait_inheritance() { + let src = r#" + pub trait Foo { + fn foo(self) -> Field; + } + + pub trait Bar { + fn bar(self) -> Field; + } + + pub trait Baz: Foo + Bar { + fn baz(self) -> Field; + } + + pub fn foo(baz: T) -> (Field, Field, Field) where T: Baz { + (baz.foo(), baz.bar(), baz.baz()) + } + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn trait_inheritance_with_generics() { + let src = r#" + trait Foo { + fn foo(self) -> T; + } + + trait Bar: Foo { + fn bar(self); + } + + pub fn foo(x: T) -> i32 where T: Bar { + x.foo() + } + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn trait_inheritance_with_generics_2() { + let src = r#" + pub trait Foo { + fn foo(self) -> T; + } + + pub trait Bar: Foo { + fn bar(self) -> (T, U); + } + + pub fn foo(x: T) -> i32 where T: Bar { + x.foo() + } + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn trait_inheritance_with_generics_3() { + let src = r#" + trait Foo {} + + trait Bar: Foo {} + + impl Foo for () {} + + impl Bar for () {} + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn trait_inheritance_with_generics_4() { + let src = r#" + trait Foo { type A; } + + trait Bar: Foo {} + + impl Foo for () { type A = i32; } + + impl Bar for () {} + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn trait_inheritance_dependency_cycle() { + let src = r#" + trait Foo: Bar {} + trait Bar: Foo {} + fn main() {} + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + assert!(matches!( + errors[0].0, + CompilationError::ResolverError(ResolverError::DependencyCycle { .. }) + )); +} + +#[test] +fn trait_inheritance_missing_parent_implementation() { + let src = r#" + pub trait Foo {} + + pub trait Bar: Foo {} + + pub struct Struct {} + + impl Bar for Struct {} + + fn main() { + let _ = Struct {}; // silence Struct never constructed warning + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + let CompilationError::ResolverError(ResolverError::TraitNotImplemented { + impl_trait, + missing_trait: the_trait, + type_missing_trait: typ, + .. + }) = &errors[0].0 + else { + panic!("Expected a TraitNotImplemented error, got {:?}", &errors[0].0); + }; + + assert_eq!(the_trait, "Foo"); + assert_eq!(typ, "Struct"); + assert_eq!(impl_trait, "Bar"); +} diff --git a/noir/noir-repo/cspell.json b/noir/noir-repo/cspell.json index dbc5fb5a43e..6fd25a77182 100644 --- a/noir/noir-repo/cspell.json +++ b/noir/noir-repo/cspell.json @@ -194,8 +194,11 @@ "stdlib", "structs", "subexpression", + "subtrait", "subshell", "subtyping", + "supertrait", + "supertraits", "swcurve", "Taiko", "tarjan", diff --git a/noir/noir-repo/docs/docs/noir/concepts/traits.md b/noir/noir-repo/docs/docs/noir/concepts/traits.md index b3235a1a29b..9da00a77587 100644 --- a/noir/noir-repo/docs/docs/noir/concepts/traits.md +++ b/noir/noir-repo/docs/docs/noir/concepts/traits.md @@ -464,6 +464,32 @@ Since we have an impl for our own type, the behavior of this code will not chang to provide its own `impl Default for Foo`. The downside of this pattern is that it requires extra wrapping and unwrapping of values when converting to and from the `Wrapper` and `Foo` types. +### Trait Inheritance + +Sometimes, you might need one trait to use another trait’s functionality (like "inheritance" in some other languages). In this case, you can specify this relationship by listing any child traits after the parent trait's name and a colon. Now, whenever the parent trait is implemented it will require the child traits to be implemented as well. A parent trait is also called a "super trait." + +```rust +trait Person { + fn name(self) -> String; +} + +// Person is a supertrait of Student. +// Implementing Student requires you to also impl Person. +trait Student: Person { + fn university(self) -> String; +} + +trait Programmer { + fn fav_language(self) -> String; +} + +// CompSciStudent (computer science student) is a subtrait of both Programmer +// and Student. Implementing CompSciStudent requires you to impl both supertraits. +trait CompSciStudent: Programmer + Student { + fn git_username(self) -> String; +} +``` + ### Visibility By default, like functions, traits are private to the module they exist in. You can use `pub` diff --git a/noir/noir-repo/test_programs/execution_success/inline_never_basic/Nargo.toml b/noir/noir-repo/test_programs/execution_success/inline_never_basic/Nargo.toml deleted file mode 100644 index 16691770d76..00000000000 --- a/noir/noir-repo/test_programs/execution_success/inline_never_basic/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "inline_never_basic" -type = "bin" -authors = [""] -compiler_version = ">=0.27.0" - -[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/inline_never_basic/Prover.toml b/noir/noir-repo/test_programs/execution_success/inline_never_basic/Prover.toml deleted file mode 100644 index f28f2f8cc48..00000000000 --- a/noir/noir-repo/test_programs/execution_success/inline_never_basic/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = "5" -y = "10" diff --git a/noir/noir-repo/test_programs/execution_success/inline_never_basic/src/main.nr b/noir/noir-repo/test_programs/execution_success/inline_never_basic/src/main.nr deleted file mode 100644 index 1922aaedb6c..00000000000 --- a/noir/noir-repo/test_programs/execution_success/inline_never_basic/src/main.nr +++ /dev/null @@ -1,8 +0,0 @@ -fn main(x: Field, y: pub Field) { - basic_check(x, y); -} - -#[inline(never)] -fn basic_check(x: Field, y: Field) { - assert(x != y); -} diff --git a/noir/noir-repo/test_programs/execution_success/regression_5462/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_5462/Nargo.toml new file mode 100644 index 00000000000..97015f78963 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/regression_5462/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_5462" +type = "bin" +authors = [""] +compiler_version = ">=0.35.0" + +[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/regression_5462/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_5462/src/main.nr new file mode 100644 index 00000000000..092f7ab96a5 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/regression_5462/src/main.nr @@ -0,0 +1,11 @@ +fn main() { + let empty_slice: [u8] = &[]; + + if empty_slice != &[] { + let _ = empty_slice.pop_front(); + } + + if empty_slice.len() != 0 { + let _ = empty_slice.pop_front(); + } +} diff --git a/noir/noir-repo/test_programs/execution_success/slice_regex/src/main.nr b/noir/noir-repo/test_programs/execution_success/slice_regex/src/main.nr index 15768248473..3b860839a6e 100644 --- a/noir/noir-repo/test_programs/execution_success/slice_regex/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/slice_regex/src/main.nr @@ -208,7 +208,7 @@ fn main() { let result = three_ones_regex.match("1111".as_bytes().as_slice()); println(result); assert_eq(result, Match { succeeded: true, match_ends: 3, leftover: &[] }); - // TODO(https://github.com/noir-lang/noir/issues/5462): re-enable these cases and complete the test using array_regex below + // TODO(https://github.com/noir-lang/noir/issues/6285): re-enable these cases and complete the test using array_regex below // // // 1* // let ones_regex: Star, 5> = Star { inner: "1" }; @@ -279,7 +279,9 @@ fn main() { // }); } -// array_regex: use to complete test once https://github.com/noir-lang/noir/issues/5462 is resolved +// TODO +// array_regex execution_success test: +// use to complete test once https://github.com/noir-lang/noir/issues/6285 is resolved // // // offset <= len <= N // struct Bvec { diff --git a/noir/noir-repo/test_programs/execution_success/trait_inheritance/Nargo.toml b/noir/noir-repo/test_programs/execution_success/trait_inheritance/Nargo.toml new file mode 100644 index 00000000000..b8390fc800d --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/trait_inheritance/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "trait_inheritance" +type = "bin" +authors = [""] +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/trait_inheritance/Prover.toml b/noir/noir-repo/test_programs/execution_success/trait_inheritance/Prover.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/test_programs/execution_success/trait_inheritance/src/main.nr b/noir/noir-repo/test_programs/execution_success/trait_inheritance/src/main.nr new file mode 100644 index 00000000000..1d17d386189 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/trait_inheritance/src/main.nr @@ -0,0 +1,33 @@ +trait Foo { + fn foo(self) -> Field; +} + +trait Bar: Foo { + fn bar(self) -> Field { + self.foo() + 1 + } + + fn baz(self) -> Field; +} + +struct Struct { + x: Field, +} + +impl Foo for Struct { + fn foo(self) -> Field { + self.x + } +} + +impl Bar for Struct { + fn baz(self) -> Field { + self.foo() + 2 + } +} + +fn main() { + let s = Struct { x: 1 }; + assert_eq(s.bar(), 2); + assert_eq(s.baz(), 3); +} diff --git a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Nargo.toml b/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Nargo.toml deleted file mode 100644 index 8fce1bf44b6..00000000000 --- a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "verify_honk_proof" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Prover.toml b/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Prover.toml deleted file mode 100644 index 45a84c26eb8..00000000000 --- a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/Prover.toml +++ /dev/null @@ -1,4 +0,0 @@ -key_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" -proof = ["0x0000000000000000000000000000000000000000000000000000000000000040", "0x0000000000000000000000000000000000000000000000000000000000000011", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000042ab5d6d1986846cf", "0x00000000000000000000000000000000000000000000000b75c020998797da78", "0x0000000000000000000000000000000000000000000000005a107acb64952eca", "0x000000000000000000000000000000000000000000000000000031e97a575e9d", "0x00000000000000000000000000000000000000000000000b5666547acf8bd5a4", "0x00000000000000000000000000000000000000000000000c410db10a01750aeb", "0x00000000000000000000000000000000000000000000000d722669117f9758a4", "0x000000000000000000000000000000000000000000000000000178cbf4206471", "0x000000000000000000000000000000000000000000000000e91b8a11e7842c38", "0x000000000000000000000000000000000000000000000007fd51009034b3357f", "0x000000000000000000000000000000000000000000000009889939f81e9c7402", "0x0000000000000000000000000000000000000000000000000000f94656a2ca48", "0x000000000000000000000000000000000000000000000006fb128b46c1ddb67f", "0x0000000000000000000000000000000000000000000000093fe27776f50224bd", "0x000000000000000000000000000000000000000000000004a0c80c0da527a081", "0x0000000000000000000000000000000000000000000000000001b52c2020d746", "0x0000000000000000000000000000005a9bae947e1e91af9e4033d8d6aa6ed632", "0x000000000000000000000000000000000025e485e013446d4ac7981c88ba6ecc", "0x000000000000000000000000000000ff1e0496e30ab24a63b32b2d1120b76e62", "0x00000000000000000000000000000000001afe0a8a685d7cd85d1010e55d9d7c", "0x000000000000000000000000000000b0804efd6573805f991458295f510a2004", "0x00000000000000000000000000000000000c81a178016e2fe18605022d5a8b0e", "0x000000000000000000000000000000eba51e76eb1cfff60a53a0092a3c3dea47", "0x000000000000000000000000000000000022e7466247b533282f5936ac4e6c15", "0x00000000000000000000000000000071b1d76edf770edff98f00ff4deec264cd", "0x00000000000000000000000000000000001e48128e68794d8861fcbb2986a383", "0x000000000000000000000000000000d3a2af4915ae6d86b097adc377fafda2d4", "0x000000000000000000000000000000000006359de9ca452dab3a4f1f8d9c9d98", "0x0000000000000000000000000000006cf7dd96d7636fda5953191b1ad776d491", "0x00000000000000000000000000000000001633d881a08d136e834cb13a28fcc6", "0x00000000000000000000000000000001254956cff6908b069fca0e6cf1c47eb1", "0x000000000000000000000000000000000006f4d4dd3890e997e75e75886bf8f7", "0x0000000000000000000000000000006cf7dd96d7636fda5953191b1ad776d491", "0x00000000000000000000000000000000001633d881a08d136e834cb13a28fcc6", "0x00000000000000000000000000000001254956cff6908b069fca0e6cf1c47eb1", "0x000000000000000000000000000000000006f4d4dd3890e997e75e75886bf8f7", "0x000000000000000000000000000000f968b227a358a305607f3efc933823d288", "0x00000000000000000000000000000000000eaf8adb390375a76d95e918b65e08", "0x000000000000000000000000000000bb34b4b447aae56f5e24f81c3acd6d547f", "0x00000000000000000000000000000000002175d012746260ebcfe339a91a81e1", "0x00000000000000000000000000000052eebbd1f6f7554e837f60c44000ed14b6", "0x00000000000000000000000000000000001c1c045a3ec94b8801f2272cc0b3f4", "0x0000000000000000000000000000004d2ef74134578f6b431a9df071ffca4292", "0x0000000000000000000000000000000000291326ade7aa6f0dfc8900eab5580b", "0x0000000000000000000000000000002433eec6418a6dba820c9527e2581fc8bc", "0x00000000000000000000000000000000000e88b7daad19af2ac2f9bdf9e50ee2", "0x000000000000000000000000000000dcfce2c427155cc3e4d035735d3dd5ece8", "0x00000000000000000000000000000000002d7d473cac1a15d0fee8b22c1a7b3e", "0x1a4249b90be4602c8ff40c7c276160ee41b2a0f8a238ce7706e9face2db03d48", "0x162204b9d54d3ffd285c393a5a1ff76ee681474fd780a21a3cf7fac5c24fc2b9", "0x30279eb953d8ee79b2155c69c04e6443c5de6bf7e02886256dd7b3cd3c9502a4", "0x0d32c1bd21baf43e72d5d82d461ef54833807ff81a877adc822f27a6db88d754", "0x0fe15e055c0803d5ebe6dd77689b70cfd82138f008810ce24535c992daaff27d", "0x1fba82c012671212ce2fc13fd09bf8fba4f7d5875ab8d37495d1ccfcff287331", "0x090738a5842fa4d2699b3726aa0dd97cb59569b4be2c6825335ec4969f859dc2", "0x0c6cb72dabbc28abcf4a50c203534e066c29f48c24ca64d672092f263df3f9d7", "0x0f27fbea0d9145f815c288b50fe7e8c10b8185d325b5264624fd57102855d05d", "0x2a815cd3fd1c43c72ee0130465250ff771d1e7be2347e4ada331b83265a03450", "0x148b4ecf2ad7ed17409417086867ee27bc1b0906dbc9cbb3714c285071e2db70", "0x08e700a42b1d6d36ee65f8ebedf47d3a44463ff9fa579dce13b7492e20142c3a", "0x2e23c69521d572ff2152c50f8c9a9191535f4cf37f95f1e0428692e78842b642", "0x14519e0354365923fb41400c19866135b45e975d56a0980260bc99f0390b1d5f", "0x04caded1f05738f736cb5bcf08d785e395e58eb7738523a20638aa16bc51593e", "0x28787eaccd38383215ea21ec02895c32d979f68ca155f534a2e2d377bff6698b", "0x20a1b81fa96c58cf11c5762c5ceb731efdcb081fca2d34d5c463d2cf40e6da18", "0x11789a06fe3bf53833741d180f068d29534d5bb58a5c64b8119542e62b189fb4", "0x23d00fcd032ace719ffcbc513bfa177a55b04377d76455c2788d999d05d011e2", "0x01f0e81b57b4a73cc118e51ede18f8724debf25c2d109db6ef45280f99f1a3fa", "0x156d1c9b61749810de728f259c2c1c1fd4dbff97101426e26087ca461c93307c", "0x1c5d619ac3a478cfd06d5eebfd879960bb321236be173813f5e78d1366d32c69", "0x250cfae4e1dfc551406f1f3d10b649a637dcb7bcb0f6f697994cf96afd35d0c1", "0x242b999f58cf5f53c874d1092bd38725aa9ea076f5bc8f176efa9ea23393874b", "0x2e15748255c4a5e0e9fe38047341b692a967257de27a85a3a38681bc9f1602ea", "0x01ef83886ea7017253699cb6371988eb8e21b4f7023d7479ece4907fe6d4a6fd", "0x08db2dbc271e375b9312f695c59c48f313235b3432cad50921c8d9ad6dd7ad7a", "0x199309f2c2cd45c15a4abb0e6554a1615ff5a6e9488a8d900bbf835fc8f664ef", "0x074be7a3d88e31ab1b59c9208c012bcfb1f85f351c709e68134996891db52b57", "0x301b1011354d2ebf46134fc4d6d734bb6ed8542d719f38f5e09a376a580cad7f", "0x12968f3eccaa27e44f14d5aaac6ecb70c00d040e07536292e685d7cab03fc563", "0x2110a023c8c22fd2ed70270a2d0a265b92a32ce2217ffe1be9a5d7d5c25f512f", "0x1e8cf4c60c53900f0430d5b44de5804fe8b38299bc803beeb4216e1a289cf624", "0x12301cb908ccb28a2616e29b831ec7105b5d3ebf45ff5fe91d50a9dd53a50b52", "0x0f1029ed107d84ff2d6d4a416cbd01da3f3d7bf5b2209ce93ba424f4b85616fc", "0x1b431d016611b8abd684afd9e92331c3325967b1116bfa91d4f44e2f8e2c9fc2", "0x281e335a0fd117064c8ace3f01e02b134a19e9b9220571ebfaaaa0e3a12d34db", "0x22559c106f77e2ae95677d5e38e288343e3b7168371aec7d3aaab9ef8150af70", "0x13f113b1d9b590149cf08c3f6e90589cda5c7b98528866b891256cb9d5d814e7", "0x10252ef388e4c80246962e98b9e976fab2cd25e1e6f1e3fd2a7d4786c5218a97", "0x16b890723dfdebd9912a9207255f95cb800222165b6fae97ec46e461f23e83f3", "0x25caf77c7d2e8e069341ec90f3c8f6d64319cfd2d77cab0625cf0377285ba11c", "0x016c84288b0bc3c50eebbe250cdd5a4ee50b2c65a24ac64d0c930cbdecb95141", "0x20a537c045b069d47dc6315f45b391f60681222381e5059ec7c8b17bf677d911", "0x2594c0edfcd4064d215a3d797bc8e3b2f401c61f3961ae96ccbec8f8fd29e81f", "0x1c831d7047483ca00ed59bdb84c47ffb8bbebbae92aa164c7b35fcffbb8a35d3", "0x2ea7f60de52b8cd6b0bd06f861fc1f2c5ed1d1fbfa53caccdb836400a03df434", "0x275c6c8bd115f7d2ce196439e2330fad305c6745bab0bf1ce3f2fa32dadc3c43", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x2b3f4e210619347288731e7f0eea1ae60dd8696fe87319044864d099a03a9536", "0x0fecd3d2aebedeb8be2b0b7e3a74de9ec8bd2cb72851541463729e0715aef48b", "0x10bee385ad0c2cd3ff88ef4d630840749e4367f9add4a300fc4f545a7778e92c", "0x1fe792730eeafbd22c4eb80e86e2b40108b1e55b2a08db786289eea5745b9e3b", "0x04d411679da432816b213cd5580dda1fd6c2f258684c036be19b5b26baca583c", "0x159f17b655d2b8a803e0cfb564918628be52d3baa950ca1b127854491624f8f4", "0x225340463867d9252a1269013536e2e1dd219aa18eadef13c324b63d44679334", "0x1885e231554e02abb40ed54b72ebf09b883d0298a6bc06fc645a30365f370ef2", "0x233344517f25170972b8ba35d01f2df2e073d322993abce7df26796126e93498", "0x08990e8faa13b18b4433ec417c5cc596885e11ffd372d5f612c08cc79a5d5c80", "0x1e960a0c892b755c28e21dcbed816c1b182d7da43bae07f8ee622bd4485f79e7", "0x27b58e2ee290a179d349ace82752528b2ff946d60c092b99ef42f53c25d0c99f", "0x2a5cf8a3193107d982edd253002c7a52ab876b445dde8307ab78fbdca022d93c", "0x2b1ab4d5277f8c82750c1c7bd043889b71465ec64a9afc1bfa37d06b1ebd0725", "0x2a0dbf5c4373a58a83d5f2a031ea0615bf12800e33b70c3191a7cbb15966ced8", "0x1f272bb4a19d14a0abdfebc9fc83125e10623b9aef730f8d25f2bf5bead38ea9", "0x2c2339cf0ae7aff56091a568c1e2c3f01f52d8ed13400737fd31eaabcaffb9bd", "0x21f5fefe6b5fa0b5da71089befb74a1a39e52b4f830cb330c3c284e154614dfd", "0x1e6f6ba4b2444586b380dc4e2b3fad111ff1f4754420a846f53ea0789ebfb0ad", "0x1193d170b0b2dd0c4a04331a4b4aa3f12920f182ec3ab547837e30f1116ca584", "0x00000000000000000000000000000025704a15c9e2ce8a69558e7bbcdcbc7784", "0x2e5d36112770fb6c985681cafe40a8c99ad13f702309e7969801dd0ed080e727", "0x0eefc2585f591bb457183134e19ad643966272234d645514bf7868d6dd8ae2cb", "0x300803e4e2339ad39b9c31f228949bbeaf9c74b7101e7be1930b088126247eaa", "0x2bb562a50ed944b438b83b01f200101a34faef7f296a75c84c731755ebddbc1a", "0x1288e0b9c742af39cbcac21357c1b29511b0bbdd3d0e3cf5e14b2eef68a28ab3", "0x20f089131cc96d86ff1cfb67fa3f51670f4bad30158751b2587354bbec76cdf9", "0x1a26c6d3e633f9bf8434cf755b5f1217dad0d455071a97a7bcf85b824f5cf07a", "0x0d7e9b8a51fccf910ec25bdbd13e70b34bd6ea6f4d629fa744f9cdf5f2beb1cf", "0x0b40f28ce428e64df9cf5a024133fc420f39decf5f6af020cc3211ab298d4631", "0x0ca4f189dde7a55fe829f46681232904f6670249a22e0deb47222bd309523a8a", "0x2c544f2e31143783977645edb2a6bdb39b875053963bfa1a5b3ae9de204a7ebe", "0x00aae4454eb48fb18ff60db6b9d015abea2e770a2f7d86d121522b834c791ba5", "0x07d74e351fd4cccf4e18475d25211efa8a359066fc693a5c8505ddb507e4b74b", "0x07d74e351fd4cccf4e18475d25211efa8a359066fc693a5c8505ddb507e4b74b", "0x2d9e5bff47207d82533e2445959941181cc890c5779bc7f24d6e8a7b9e425b5c", "0x0aea3c0c317c441a5775a9849108d7a6889b39128235f717b09b184aa08e4eb7", "0x1ca5bc6fb37c55a562f4991901c39902f42d14db71284116df74cb4e7d55e493", "0x220fed26d64cd69f40e6d145a423e4a3c8cd0dce747e7d51647441270ad4d774", "0x15be574c9358889257aa2a30ff7b5fcc31a57da7032296e2c1201c49a44bbdb6", "0x2de539925525bedd3b7f43a9c6bf0f713151a17f79ac7ff4a9cd27b15ffe892a", "0x083086693dbf465211741e2cbff70ff38eb08383faf22d397eb2742c8ad7396a", "0x1fdfa258a890598816e807c50058d7a1462edd5ff196a2eae0f862e454b49aa1", "0x10c434c6daaa8226fa8e3e302123dfdc4455cf68063df518949df5a65a945213", "0x0000000000000000000000000000006472a7874de2c454a4591ed7784df1c104", "0x000000000000000000000000000000000008c46ac53d2c4ad0c26a5d6c790082", "0x0000000000000000000000000000005e422f9cfb8725800de60dfe0a8d4104c0", "0x000000000000000000000000000000000000f10fd4e4de81a0c00073ec91c274", "0x000000000000000000000000000000b20813090eca76bc6aa4a699b1ec8d5d6d", "0x0000000000000000000000000000000000292cc9f8a744eb00e0903c29ce87a7", "0x000000000000000000000000000000350a368b415fbb99fa90a26a42b1a3affd", "0x0000000000000000000000000000000000280eb9275cb05a3435f464d1dc369d", "0x000000000000000000000000000000280df6505e20c7725fe6d29439f96ee05d", "0x000000000000000000000000000000000017ef5033a08535451e2747827aa94b", "0x0000000000000000000000000000002f9ba89ae91b4e4a4ff8ccbd0526faad2f", "0x00000000000000000000000000000000001c2013561dafcc02cb03220bdf23c4", "0x000000000000000000000000000000aac102c400f9e5da0321ded4510994434b", "0x00000000000000000000000000000000001ec8ab9cc834b492fde124962f04a1", "0x0000000000000000000000000000000673dbd698da8b8cce450d2a083aba9987", "0x00000000000000000000000000000000000a49e55bb040249cb41c63cea901cd", "0x000000000000000000000000000000133d92af8d76ee0c74a12081ee7b2ef8c4", "0x0000000000000000000000000000000000240f552d1c6cbb007650e4b142e0a5", "0x000000000000000000000000000000e29c6e7d982ec08d51c79d6261c28d742d", "0x000000000000000000000000000000000021baeec04d9be419c923626034e7b3", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x1e940a528b42d8230e7d4dff76262a80986c0d00b2c02a9bc0559e36212d1547", "0x1ceccf21ac39f70d76ad6f7fe0dcb33b6af04555a0b1959e4714d65925e4e253", "0x096139d757046cdbdb7ee89a95f112f70882a43a46c2f739d9be115dda013420", "0x2f9c8ac67c7825b08eff0e7f7656a671f4c64e5601f2efab35b1b795801eec04", "0x2077e648e1704851cdffd7e6e56311634a7b741bab77ca34d9dff12a6a2bfe99", "0x115d48c4a97aeb3c447a060f9e0d675b0dc7f4a05a3f5776e2f279f3a165d7dc", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000000000fd38c45c3ec5b841482a80e3a56ce82555", "0x00000000000000000000000000000000000ad70b03f092f60af3e0ce1bb29d2c", "0x0000000000000000000000000000007a184d5342c90c634c0b1a050f0b97c9fb", "0x0000000000000000000000000000000000271f42abcb3bc1f0332e4b3ca85e1d", "0x0000000000000000000000000000008256322bbe2c1b8cd9d84e5ff6123477f2", "0x000000000000000000000000000000000025cab962761681dd9547f4c78814df", "0x0000000000000000000000000000008c4234510e5825c02b9ac427bcbf8e279a", "0x000000000000000000000000000000000013a14e0d7fc073c44643af38cc5396"] -public_inputs = ["0x0000000000000000000000000000000000000000000000000000000000000003"] -verification_key = ["0x0000000000000000000000000000000000000000000000000000000000000040", "0x0000000000000000000000000000000000000000000000000000000000000011", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000003", "0x0000000000000000000000000000000000000000000000000000000000000004", "0x0000000000000000000000000000000000000000000000000000000000000005", "0x0000000000000000000000000000000000000000000000000000000000000006", "0x0000000000000000000000000000000000000000000000000000000000000007", "0x0000000000000000000000000000000000000000000000000000000000000008", "0x0000000000000000000000000000000000000000000000000000000000000009", "0x000000000000000000000000000000000000000000000000000000000000000a", "0x000000000000000000000000000000000000000000000000000000000000000b", "0x000000000000000000000000000000000000000000000000000000000000000c", "0x000000000000000000000000000000000000000000000000000000000000000d", "0x000000000000000000000000000000000000000000000000000000000000000e", "0x000000000000000000000000000000000000000000000000000000000000000f", "0x0000000000000000000000000000000000000000000000000000000000000010", "0x00000000000000000000000000000060e430ad1c23bfcf3514323aae3f206e84", "0x00000000000000000000000000000000001b5c3ff4c2458d8f481b1c068f27ae", "0x000000000000000000000000000000bb510ab2112def34980e4fc6998ad9dd16", "0x00000000000000000000000000000000000576e7c105b43e061e13cb877fefe1", "0x000000000000000000000000000000ced074785d11857b065d8199e6669a601c", "0x00000000000000000000000000000000000053b48a4098c1c0ae268f273952f7", "0x000000000000000000000000000000d1d4b26e941db8168cee8f6de548ae0fd8", "0x00000000000000000000000000000000001a9adf5a6dadc3d948bb61dfd63f4c", "0x0000000000000000000000000000009ce1faac6f8de6ebb18f1db17372c82ad5", "0x00000000000000000000000000000000002002681bb417184b2df070a16a3858", "0x000000000000000000000000000000161baa651a8092e0e84725594de5aba511", "0x00000000000000000000000000000000000be0064399c2a1efff9eb0cdcb2223", "0x0000000000000000000000000000008673be6fd1bdbe980a29d8c1ded54381e7", "0x000000000000000000000000000000000008a5158a7d9648cf1d234524c9fa0c", "0x0000000000000000000000000000002b4fce6e4b1c72062b296d49bca2aa4130", "0x00000000000000000000000000000000002e45a9eff4b6769e55fb710cded44f", "0x00000000000000000000000000000072b85bf733758b76bcf97333efb85a23e3", "0x000000000000000000000000000000000017da0ea508994fc82862715e4b5592", "0x00000000000000000000000000000094fa74695cf058dba8ff35aec95456c6c3", "0x0000000000000000000000000000000000211acddb851061c24b8f159e832bd1", "0x000000000000000000000000000000303b5e5c531384b9a792e11702ad3bcab0", "0x00000000000000000000000000000000000d336dff51a60b8833d5d7f6d4314c", "0x0000000000000000000000000000009f825dde88092070747180d581c342444a", "0x0000000000000000000000000000000000237fbd6511a03cca8cac01b555fe01", "0x0000000000000000000000000000007c313205159495df6d8de292079a4844ff", "0x000000000000000000000000000000000018facdfc468530dd45e8f7a1d38ce9", "0x0000000000000000000000000000000d1ce33446fc3dc4ab40ca38d92dac74e1", "0x00000000000000000000000000000000000852d8e3e0e8f4435af3e94222688b", "0x0000000000000000000000000000006c04ee19ec1dfec87ed47d6d04aa158de2", "0x000000000000000000000000000000000013240f97a584b45184c8ec31319b5f", "0x000000000000000000000000000000cefb5d240b07ceb4be26ea429b6dc9d9e0", "0x00000000000000000000000000000000002dad22022121d689f57fb38ca21349", "0x000000000000000000000000000000c9f189f2a91aeb664ce376d8b157ba98f8", "0x00000000000000000000000000000000002531a51ad54f124d58094b219818d2", "0x000000000000000000000000000000ef1e6db71809307f677677e62b4163f556", "0x0000000000000000000000000000000000272da4396fb2a7ee0638b9140e523d", "0x0000000000000000000000000000002e54c0244a7732c87bc4712a76dd8c83fb", "0x000000000000000000000000000000000007db77b3e04b7eba9643da57cbbe4d", "0x000000000000000000000000000000e0dfe1ddd7f74ae0d636c910c3e85830d8", "0x00000000000000000000000000000000000466fa9b57ec4664abd1505b490862", "0x0000000000000000000000000000009ee55ae8a32fe5384c79907067cc27192e", "0x00000000000000000000000000000000000799d0e465cec07ecb5238c854e830", "0x0000000000000000000000000000001d5910ad361e76e1c241247a823733c39f", "0x00000000000000000000000000000000002b03f2ccf7507564da2e6678bef8fe", "0x000000000000000000000000000000ee40d90bea71fba7a412dd61fcf34e8ceb", "0x0000000000000000000000000000000000140b0936c323fd2471155617b6af56", "0x0000000000000000000000000000002b90071823185c5ff8e440fd3d73b6fefc", "0x00000000000000000000000000000000002b6c10790a5f6631c87d652e059df4", "0x00000000000000000000000000000029a17181c7934fc3fdbd352eac5cb521b9", "0x00000000000000000000000000000000001f497cbf5284ff29a2d336e5991999", "0x000000000000000000000000000000072bd9c0c6beda1fdee6d4ff0432ba9e1b", "0x000000000000000000000000000000000013ea38a0bd2aa751a490a724fac818", "0x000000000000000000000000000000c599f63dcd3edd49f08ae5c3141c1e3493", "0x00000000000000000000000000000000002bdb36be0bea09950dd32a8ccf6fbc", "0x00000000000000000000000000000047f27f29724e7f19eba0340256a0bd4b7d", "0x00000000000000000000000000000000001c1c5ccf87a962129ca785f8f35120", "0x000000000000000000000000000000c5c71efdae00679bbe4a95096e012b1817", "0x000000000000000000000000000000000017a365de041e317817d0135f2b48e0", "0x0000000000000000000000000000008ae711ac402f7848d719c93a89ba8d39f1", "0x00000000000000000000000000000000002b6fb40ed8a1935226f4f9786a0499", "0x0000000000000000000000000000002f03a71501d83de1da5715a4e9462d6198", "0x00000000000000000000000000000000001644064443b8546f48eae693af47b8", "0x00000000000000000000000000000083763ab1b6e8fe269b2fe4c7b9c448c08d", "0x000000000000000000000000000000000021d7cc18c59676a8eeb47c0111c251", "0x000000000000000000000000000000b5f937153073e03ea7d51a996e0ebc2e6b", "0x000000000000000000000000000000000011ddd0e26457373eb06e0493177672", "0x000000000000000000000000000000c5f6eb9f6fc8fa99811a4a88c74a6d018b", "0x000000000000000000000000000000000025bcd07a0732c123567834f5109558", "0x000000000000000000000000000000aeb08a0b1a4442189448b4e97490568146", "0x000000000000000000000000000000000002a1744e4771705536a88f07e0f90f", "0x000000000000000000000000000000b938568293bd0724b0ea76c2ec34c4a829", "0x0000000000000000000000000000000000053296e8f3b9ad3af877dfa9c7c2a7", "0x000000000000000000000000000000f0ca1db6323996eba26bdc86dafef9d10b", "0x00000000000000000000000000000000001441a46c58af03d5645d52721d956a", "0x0000000000000000000000000000008bbf8f884013c66c28ba09c2fbd573b656", "0x0000000000000000000000000000000000206c391ca06fac27d1908e94570243", "0x0000000000000000000000000000002d4f5aaed88ba4f79612d53b804ca8f194", "0x00000000000000000000000000000000001674011c96392df08970fa6b7b4cb8", "0x0000000000000000000000000000009f88297c1729d76c4d9306853598c91325", "0x0000000000000000000000000000000000256f51adfcacc3c1e340be4d32d3e9", "0x0000000000000000000000000000000ab9955eec0d74eb799afed2a802b24d75", "0x00000000000000000000000000000000001fcbe43ea105b30d36ed0b21b03411", "0x000000000000000000000000000000d66b1d5433f1aa5305cd1edce7c22de466", "0x00000000000000000000000000000000002331546a256b8a3b751956806680d4", "0x000000000000000000000000000000e97954ad6cd6f45fb15c91434121db4304", "0x00000000000000000000000000000000002e20a97e09d50f227ced47e7a98250", "0x0000000000000000000000000000001ebbc27eb9ebededefba79522eb58ae89b", "0x0000000000000000000000000000000000090efa4974e566e81d1177b85a30be", "0x0000000000000000000000000000005eafa070b9c9632404052642e3bc14f9fd", "0x00000000000000000000000000000000001489068864102daca6a6b8bc4d448b", "0x0000000000000000000000000000009ebc91aaaac036a6477cadbe54e8556dfd", "0x00000000000000000000000000000000000ef6d835e2ed3343b95c82c8c54037", "0x00000000000000000000000000000033b28b529dff46e93af4e7422530478e4a", "0x000000000000000000000000000000000020a86c2f8591bf190bcddcc03c42fb", "0x000000000000000000000000000000a9679d0acc088f7dc27bf6d866bcd2dda2", "0x00000000000000000000000000000000002fb9d0d2d4099402bed74f738f64cc", "0x00000000000000000000000000000023b09f876a29a061582848a8b9a5870c12", "0x00000000000000000000000000000000001d5bb906f03f0d49e9c4791bc43af9", "0x00000000000000000000000000000017aac9854ea240d8ec97bf760c4d4ba870", "0x00000000000000000000000000000000000b227a556c414ada0dc75bb303e30e", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000009b624fa65d1a24b7f14a8f25f3789622af", "0x000000000000000000000000000000000013d47bff8c630e847b70e2732fd3f0", "0x00000000000000000000000000000061d21663e93132f32921075f4c936a84df", "0x00000000000000000000000000000000001a74ca4e118fb480b9b999902989a3"] diff --git a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/src/main.nr b/noir/noir-repo/test_programs/execution_success/verify_honk_proof/src/main.nr deleted file mode 100644 index 152b2dafef8..00000000000 --- a/noir/noir-repo/test_programs/execution_success/verify_honk_proof/src/main.nr +++ /dev/null @@ -1,22 +0,0 @@ - -// This circuit aggregates a single Honk proof from `assert_statement_recursive`. -global SIZE_OF_PROOF_IF_LOGN_IS_28 : u32 = 463; -global HONK_IDENTIFIER : u32 = 1; -fn main( - verification_key: [Field; 128], - // This is the proof without public inputs attached. - // This means: the size of this does not change with the number of public inputs. - proof: [Field; SIZE_OF_PROOF_IF_LOGN_IS_28], - public_inputs: pub [Field; 1], - // This is currently not public. It is fine given that the vk is a part of the circuit definition. - // I believe we want to eventually make it public too though. - key_hash: Field -) { - std::verify_proof_with_type( - verification_key, - proof, - public_inputs, - key_hash, - HONK_IDENTIFIER - ); -} diff --git a/noir/noir-repo/tooling/lsp/src/notifications/mod.rs b/noir/noir-repo/tooling/lsp/src/notifications/mod.rs index 6cddd278e62..d228eb564e6 100644 --- a/noir/noir-repo/tooling/lsp/src/notifications/mod.rs +++ b/noir/noir-repo/tooling/lsp/src/notifications/mod.rs @@ -6,11 +6,12 @@ use crate::{ insert_all_files_for_workspace_into_file_manager, PackageCacheData, WorkspaceCacheData, }; use async_lsp::{ErrorCode, LanguageClient, ResponseError}; -use fm::{FileManager, FileMap}; +use fm::{FileId, FileManager, FileMap}; use fxhash::FxHashMap as HashMap; -use lsp_types::{DiagnosticTag, Url}; +use lsp_types::{DiagnosticRelatedInformation, DiagnosticTag, Url}; use noirc_driver::check_crate; -use noirc_errors::{DiagnosticKind, FileDiagnostic}; +use noirc_errors::reporter::CustomLabel; +use noirc_errors::{DiagnosticKind, FileDiagnostic, Location}; use crate::types::{ notification, Diagnostic, DiagnosticSeverity, DidChangeConfigurationParams, @@ -195,11 +196,13 @@ fn publish_diagnostics( for file_diagnostic in file_diagnostics.into_iter() { let file_id = file_diagnostic.file_id; - let diagnostic = file_diagnostic_to_diagnostic(file_diagnostic, files); - let path = fm.path(file_id).expect("file must exist to have emitted diagnostic"); if let Ok(uri) = Url::from_file_path(path) { - diagnostics_per_url.entry(uri).or_default().push(diagnostic); + if let Some(diagnostic) = + file_diagnostic_to_diagnostic(file_diagnostic, files, fm, uri.clone()) + { + diagnostics_per_url.entry(uri).or_default().push(diagnostic); + } } } @@ -228,17 +231,21 @@ fn publish_diagnostics( state.files_with_errors.insert(package_root_dir.clone(), new_files_with_errors); } -fn file_diagnostic_to_diagnostic(file_diagnostic: FileDiagnostic, files: &FileMap) -> Diagnostic { +fn file_diagnostic_to_diagnostic( + file_diagnostic: FileDiagnostic, + files: &FileMap, + fm: &FileManager, + uri: Url, +) -> Option { let file_id = file_diagnostic.file_id; let diagnostic = file_diagnostic.diagnostic; - // TODO: Should this be the first item in secondaries? Should we bail when we find a range? - let range = diagnostic - .secondaries - .into_iter() - .filter_map(|sec| byte_span_to_range(files, file_id, sec.span.into())) - .last() - .unwrap_or_default(); + if diagnostic.secondaries.is_empty() { + return None; + } + + let span = diagnostic.secondaries.first().unwrap().span; + let range = byte_span_to_range(files, file_id, span.into())?; let severity = match diagnostic.kind { DiagnosticKind::Error => DiagnosticSeverity::ERROR, @@ -255,13 +262,60 @@ fn file_diagnostic_to_diagnostic(file_diagnostic: FileDiagnostic, files: &FileMa tags.push(DiagnosticTag::DEPRECATED); } - Diagnostic { + let secondaries = diagnostic + .secondaries + .into_iter() + .filter_map(|secondary| secondary_to_related_information(secondary, file_id, files, fm)); + let notes = diagnostic.notes.into_iter().map(|message| DiagnosticRelatedInformation { + location: lsp_types::Location { uri: uri.clone(), range }, + message, + }); + let call_stack = diagnostic + .call_stack + .into_iter() + .filter_map(|frame| call_stack_frame_to_related_information(frame, files, fm)); + let related_information: Vec<_> = secondaries.chain(notes).chain(call_stack).collect(); + + Some(Diagnostic { range, severity: Some(severity), message: diagnostic.message, tags: if tags.is_empty() { None } else { Some(tags) }, + related_information: if related_information.is_empty() { + None + } else { + Some(related_information) + }, ..Default::default() - } + }) +} + +fn secondary_to_related_information( + secondary: CustomLabel, + file_id: FileId, + files: &FileMap, + fm: &FileManager, +) -> Option { + let secondary_file = secondary.file.unwrap_or(file_id); + let path = fm.path(secondary_file)?; + let uri = Url::from_file_path(path).ok()?; + let range = byte_span_to_range(files, file_id, secondary.span.into())?; + let message = secondary.message; + Some(DiagnosticRelatedInformation { location: lsp_types::Location { uri, range }, message }) +} + +fn call_stack_frame_to_related_information( + frame: Location, + files: &FileMap, + fm: &FileManager, +) -> Option { + let path = fm.path(frame.file)?; + let uri = Url::from_file_path(path).ok()?; + let range = byte_span_to_range(files, frame.file, frame.span.into())?; + Some(DiagnosticRelatedInformation { + location: lsp_types::Location { uri, range }, + message: "Error originated here".to_string(), + }) } pub(super) fn on_exit( diff --git a/noir/noir-repo/tooling/lsp/src/trait_impl_method_stub_generator.rs b/noir/noir-repo/tooling/lsp/src/trait_impl_method_stub_generator.rs index 14b40858bb1..b433ee2ec88 100644 --- a/noir/noir-repo/tooling/lsp/src/trait_impl_method_stub_generator.rs +++ b/noir/noir-repo/tooling/lsp/src/trait_impl_method_stub_generator.rs @@ -98,9 +98,9 @@ impl<'a> TraitImplMethodStubGenerator<'a> { } self.append_type(&constraint.typ); self.string.push_str(": "); - let trait_ = self.interner.get_trait(constraint.trait_id); + let trait_ = self.interner.get_trait(constraint.trait_bound.trait_id); self.string.push_str(&trait_.name.0.contents); - self.append_trait_generics(&constraint.trait_generics); + self.append_trait_generics(&constraint.trait_bound.trait_generics); } } diff --git a/noir/noir-repo/tooling/nargo/Cargo.toml b/noir/noir-repo/tooling/nargo/Cargo.toml index c5d4bbc9788..1dbb9978b0b 100644 --- a/noir/noir-repo/tooling/nargo/Cargo.toml +++ b/noir/noir-repo/tooling/nargo/Cargo.toml @@ -27,15 +27,13 @@ rayon.workspace = true jsonrpc.workspace = true rand.workspace = true serde.workspace = true +walkdir = "2.5.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] noir_fuzzer.workspace = true proptest.workspace = true [dev-dependencies] -# TODO: This dependency is used to generate unit tests for `get_all_paths_in_dir` -# TODO: once that method is moved to nargo_cli, we can move this dependency to nargo_cli -tempfile.workspace = true jsonrpc-http-server = "18.0" jsonrpc-core-client = "18.0" jsonrpc-derive = "18.0" diff --git a/noir/noir-repo/tooling/nargo/src/lib.rs b/noir/noir-repo/tooling/nargo/src/lib.rs index 0118e83d2a3..88f07e0c292 100644 --- a/noir/noir-repo/tooling/nargo/src/lib.rs +++ b/noir/noir-repo/tooling/nargo/src/lib.rs @@ -13,7 +13,10 @@ pub mod ops; pub mod package; pub mod workspace; -use std::collections::{BTreeMap, HashMap}; +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + path::PathBuf, +}; use fm::{FileManager, FILE_EXTENSION}; use noirc_driver::{add_dep, prepare_crate, prepare_dependency}; @@ -23,6 +26,7 @@ use noirc_frontend::{ }; use package::{Dependency, Package}; use rayon::prelude::*; +use walkdir::WalkDir; pub use self::errors::NargoError; @@ -58,8 +62,14 @@ pub fn insert_all_files_for_workspace_into_file_manager_with_overrides( file_manager: &mut FileManager, overrides: &HashMap<&std::path::Path, &str>, ) { + let mut processed_entry_paths = HashSet::new(); for package in workspace.clone().into_iter() { - insert_all_files_for_package_into_file_manager(package, file_manager, overrides); + insert_all_files_for_package_into_file_manager( + package, + file_manager, + overrides, + &mut processed_entry_paths, + ); } } // We will pre-populate the file manager with all the files in the package @@ -72,27 +82,55 @@ fn insert_all_files_for_package_into_file_manager( package: &Package, file_manager: &mut FileManager, overrides: &HashMap<&std::path::Path, &str>, + processed_entry_paths: &mut HashSet, ) { + if processed_entry_paths.contains(&package.entry_path) { + return; + } + processed_entry_paths.insert(package.entry_path.clone()); + // Start off at the entry path and read all files in the parent directory. let entry_path_parent = package .entry_path .parent() .unwrap_or_else(|| panic!("The entry path is expected to be a single file within a directory and so should have a parent {:?}", package.entry_path)); - // Get all files in the package and add them to the file manager - let paths = get_all_noir_source_in_dir(entry_path_parent) - .expect("could not get all paths in the package"); - for path in paths { + for entry in WalkDir::new(entry_path_parent) { + let Ok(entry) = entry else { + continue; + }; + + if !entry.file_type().is_file() { + continue; + } + + if !entry.path().extension().map_or(false, |ext| ext == FILE_EXTENSION) { + continue; + }; + + let path = entry.into_path(); + + // Avoid reading the source if the file is already there + if file_manager.has_file(&path) { + continue; + } + let source = if let Some(src) = overrides.get(path.as_path()) { src.to_string() } else { std::fs::read_to_string(path.as_path()) .unwrap_or_else(|_| panic!("could not read file {:?} into string", path)) }; + file_manager.add_file_with_source(path.as_path(), source); } - insert_all_files_for_packages_dependencies_into_file_manager(package, file_manager); + insert_all_files_for_packages_dependencies_into_file_manager( + package, + file_manager, + overrides, + processed_entry_paths, + ); } // Inserts all files for the dependencies of the package into the file manager @@ -100,6 +138,8 @@ fn insert_all_files_for_package_into_file_manager( fn insert_all_files_for_packages_dependencies_into_file_manager( package: &Package, file_manager: &mut FileManager, + overrides: &HashMap<&std::path::Path, &str>, + processed_entry_paths: &mut HashSet, ) { for (_, dep) in package.dependencies.iter() { match dep { @@ -107,9 +147,9 @@ fn insert_all_files_for_packages_dependencies_into_file_manager( insert_all_files_for_package_into_file_manager( package, file_manager, - &HashMap::new(), + overrides, + processed_entry_paths, ); - insert_all_files_for_packages_dependencies_into_file_manager(package, file_manager); } } } @@ -143,84 +183,3 @@ pub fn prepare_package<'file_manager, 'parsed_files>( (context, crate_id) } - -// Get all Noir source files in the directory and subdirectories. -// -// Panics: If the path is not a path to a directory. -fn get_all_noir_source_in_dir(dir: &std::path::Path) -> std::io::Result> { - get_all_paths_in_dir(dir, |path| { - path.extension().map_or(false, |extension| extension == FILE_EXTENSION) - }) -} - -// Get all paths in the directory and subdirectories. -// -// Panics: If the path is not a path to a directory. -// -// TODO: Along with prepare_package, this function is an abstraction leak -// TODO: given that this crate should not know about the file manager. -// TODO: We can clean this up in a future refactor -fn get_all_paths_in_dir( - dir: &std::path::Path, - predicate: fn(&std::path::Path) -> bool, -) -> std::io::Result> { - assert!(dir.is_dir(), "directory {dir:?} is not a path to a directory"); - - let mut paths = Vec::new(); - - if dir.is_dir() { - for entry in std::fs::read_dir(dir)? { - let entry = entry?; - let path = entry.path(); - if path.is_dir() { - let mut sub_paths = get_all_paths_in_dir(&path, predicate)?; - paths.append(&mut sub_paths); - } else if predicate(&path) { - paths.push(path); - } - } - } - - Ok(paths) -} - -#[cfg(test)] -mod tests { - use crate::get_all_paths_in_dir; - use std::{ - fs::{self, File}, - path::Path, - }; - use tempfile::tempdir; - - fn create_test_dir_structure(temp_dir: &Path) -> std::io::Result<()> { - fs::create_dir(temp_dir.join("sub_dir1"))?; - File::create(temp_dir.join("sub_dir1/file1.txt"))?; - fs::create_dir(temp_dir.join("sub_dir2"))?; - File::create(temp_dir.join("sub_dir2/file2.txt"))?; - File::create(temp_dir.join("file3.txt"))?; - Ok(()) - } - - #[test] - fn test_get_all_paths_in_dir() { - let temp_dir = tempdir().expect("could not create a temporary directory"); - create_test_dir_structure(temp_dir.path()) - .expect("could not create test directory structure"); - - let paths = get_all_paths_in_dir(temp_dir.path(), |_| true) - .expect("could not get all paths in the test directory"); - - // This should be the paths to all of the files in the directory and the subdirectory - let expected_paths = vec![ - temp_dir.path().join("file3.txt"), - temp_dir.path().join("sub_dir1/file1.txt"), - temp_dir.path().join("sub_dir2/file2.txt"), - ]; - - assert_eq!(paths.len(), expected_paths.len()); - for path in expected_paths { - assert!(paths.contains(&path)); - } - } -} diff --git a/noir/noir-repo/tooling/nargo_cli/tests/stdlib-props.rs b/noir/noir-repo/tooling/nargo_cli/tests/stdlib-props.rs index fb80cff6cd2..9e1a2823e70 100644 --- a/noir/noir-repo/tooling/nargo_cli/tests/stdlib-props.rs +++ b/noir/noir-repo/tooling/nargo_cli/tests/stdlib-props.rs @@ -305,7 +305,14 @@ fn fuzz_poseidon_equivalence() { for len in 1..light_poseidon::MAX_X5_LEN { let source = format!( "fn main(input: [Field; {len}]) -> pub Field {{ - std::hash::poseidon::bn254::hash_{len}(input) + let h1 = std::hash::poseidon::bn254::hash_{len}(input); + let h2 = {{ + let mut hasher = std::hash::poseidon::PoseidonHasher::default(); + input.hash(&mut hasher); + hasher.finish() + }}; + assert_eq(h1, h2); + h1 }}" ); diff --git a/noir/noir-repo/tooling/nargo_fmt/tests/expected/trait.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/trait.nr new file mode 100644 index 00000000000..0467585fac3 --- /dev/null +++ b/noir/noir-repo/tooling/nargo_fmt/tests/expected/trait.nr @@ -0,0 +1,2 @@ +trait Foo: Bar + Baz {} + diff --git a/noir/noir-repo/tooling/nargo_fmt/tests/input/trait.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/trait.nr new file mode 100644 index 00000000000..0467585fac3 --- /dev/null +++ b/noir/noir-repo/tooling/nargo_fmt/tests/input/trait.nr @@ -0,0 +1,2 @@ +trait Foo: Bar + Baz {} +