diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 75c95c06d09..b33bca33225 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -84,10 +84,10 @@ impl<'context> Elaborator<'context> { expr_type: inner_expr_type.clone(), expr_span: span, }); + } - if i + 1 == statements.len() { - block_type = stmt_type; - } + if i + 1 == statements.len() { + block_type = stmt_type; } } diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 0581e7900f8..7cf07cbc86c 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -1,19 +1,19 @@ #![allow(unused)] use std::{ - collections::{BTreeMap, BTreeSet}, + collections::{BTreeMap, BTreeSet, HashMap}, rc::Rc, }; use crate::{ ast::{ ArrayLiteral, ConstructorExpression, FunctionKind, IfExpression, InfixExpression, Lambda, - UnresolvedTraitConstraint, UnresolvedTypeExpression, + TraitItem, UnresolvedTraitConstraint, UnresolvedTypeExpression, }, hir::{ def_collector::{ dc_crate::{ - filter_literal_globals, CompilationError, UnresolvedGlobal, UnresolvedStruct, - UnresolvedTrait, UnresolvedTypeAlias, + filter_literal_globals, CompilationError, ImplMap, UnresolvedGlobal, + UnresolvedStruct, UnresolvedTrait, UnresolvedTypeAlias, }, errors::DuplicateType, }, @@ -28,6 +28,7 @@ use crate::{ HirInfixExpression, HirLambda, HirMemberAccess, HirMethodCallExpression, HirMethodReference, HirPrefixExpression, }, + function::Parameters, stmt::HirLetStatement, traits::TraitConstraint, }, @@ -80,6 +81,7 @@ mod types; use fm::FileId; use iter_extended::vecmap; +use noirc_arena::Index; use noirc_errors::{Location, Span}; use regex::Regex; use rustc_hash::FxHashSet as HashSet; @@ -226,6 +228,8 @@ impl<'context> Elaborator<'context> { this.define_type_alias(alias_id, alias); } + this.define_function_metas(&mut items.functions, &mut items.impls, &mut items.trait_impls); + this.collect_traits(items.traits); // Must resolve structs before we resolve globals. @@ -244,7 +248,7 @@ impl<'context> Elaborator<'context> { // // These are resolved after trait impls so that struct methods are chosen // over trait methods if there are name conflicts. - for ((typ, module), impls) in &items.impls { + for ((typ, module), impls) in &mut items.impls { this.collect_impls(typ, *module, impls); } @@ -268,13 +272,14 @@ impl<'context> Elaborator<'context> { let cycle_errors = this.interner.check_for_dependency_cycles(); this.errors.extend(cycle_errors); - this.errors } fn elaborate_functions(&mut self, functions: UnresolvedFunctions) { self.file = functions.file_id; self.trait_id = functions.trait_id; // TODO: Resolve? + self.self_type = functions.self_type; + for (local_module, id, func) in functions.functions { self.local_module = local_module; let generics_count = self.generics.len(); @@ -285,7 +290,6 @@ impl<'context> Elaborator<'context> { fn elaborate_function(&mut self, mut function: NoirFunction, id: FuncId) { self.current_function = Some(id); - self.resolve_where_clause(&mut function.def.where_clause); // Without this, impl methods can accidentally be placed in contracts. See #3254 if self.self_type.is_some() { @@ -297,9 +301,6 @@ impl<'context> Elaborator<'context> { // Check whether the function has globals in the local module and add them to the scope self.resolve_local_globals(); - self.add_generics(&function.def.generics); - - self.desugar_impl_trait_args(&mut function, id); self.trait_bounds = function.def.where_clause.clone(); let is_low_level_or_oracle = function @@ -312,8 +313,19 @@ impl<'context> Elaborator<'context> { self.in_unconstrained_fn = true; } - let func_meta = self.extract_meta(&function, id); + let func_meta = self.interner.func_meta.get(&id); + let func_meta = func_meta + .expect("FuncMetas should be declared before a function is elaborated") + .clone(); + for (parameter, param2) in function.def.parameters.iter().zip(&func_meta.parameters.0) { + let definition_kind = DefinitionKind::Local(None); + self.elaborate_pattern(parameter.pattern.clone(), param2.1.clone(), definition_kind); + } + + self.generics = func_meta.all_generics.clone(); + self.desugar_impl_trait_args(&mut function, id); + self.declare_numeric_generics(&func_meta.parameters, func_meta.return_type()); self.add_trait_constraints_to_scope(&func_meta); let (hir_func, body_type) = match function.kind { @@ -369,7 +381,6 @@ impl<'context> Elaborator<'context> { self.trait_bounds.clear(); - self.interner.push_fn_meta(func_meta, id); self.interner.update_fn(id, hir_func); self.current_function = None; } @@ -531,9 +542,23 @@ impl<'context> Elaborator<'context> { /// Extract metadata from a NoirFunction /// to be used in analysis and intern the function parameters - /// Prerequisite: self.add_generics() has already been called with the given - /// function's generics, including any generics from the impl, if any. - fn extract_meta(&mut self, func: &NoirFunction, func_id: FuncId) -> FuncMeta { + /// Prerequisite: any implicit generics, including any generics from the impl, + /// have already been added to scope via `self.add_generics`. + fn define_function_meta(&mut self, func: &mut NoirFunction, func_id: FuncId) { + self.current_function = Some(func_id); + self.resolve_where_clause(&mut func.def.where_clause); + + // Without this, impl methods can accidentally be placed in contracts. See #3254 + if self.self_type.is_some() { + self.in_contract = false; + } + + self.scopes.start_function(); + self.current_item = Some(DependencyId::Function(func_id)); + + // Check whether the function has globals in the local module and add them to the scope + self.resolve_local_globals(); + let location = Location::new(func.name_ident().span(), self.file); let id = self.interner.function_definition_id(func_id); let name_ident = HirIdent::non_trait_method(id, location); @@ -558,6 +583,8 @@ impl<'context> Elaborator<'context> { let has_inline_attribute = has_no_predicates_attribute || should_fold; let is_entry_point = self.is_entry_point_function(func); + self.add_generics(&func.def.generics); + let mut generics = vecmap(&self.generics, |(_, typevar, _)| typevar.clone()); let mut parameters = vec![]; let mut parameter_types = vec![]; @@ -586,8 +613,6 @@ impl<'context> Elaborator<'context> { let return_type = Box::new(self.resolve_type(func.return_type())); - self.declare_numeric_generics(¶meter_types, &return_type); - if !self.pub_allowed(func) && func.def.return_visibility == Visibility::Public { self.push_err(ResolverError::UnnecessaryPub { ident: func.name_ident().clone(), @@ -640,12 +665,13 @@ impl<'context> Elaborator<'context> { .map(|(name, typevar, _span)| (name.clone(), typevar.clone())) .collect(); - FuncMeta { + let meta = FuncMeta { name: name_ident, kind: func.kind, location, typ, direct_generics, + all_generics: self.generics.clone(), trait_impl: self.current_trait_impl, parameters: parameters.into(), return_type: func.def.return_type.clone(), @@ -654,7 +680,12 @@ impl<'context> Elaborator<'context> { trait_constraints: self.resolve_trait_constraints(&func.def.where_clause), is_entry_point, has_inline_attribute, - } + }; + + self.interner.push_fn_meta(meta, func_id); + self.current_function = None; + self.scopes.end_function(); + self.current_item = None; } /// Only sized types are valid to be used as main's parameters or the parameters to a contract @@ -694,7 +725,7 @@ impl<'context> Elaborator<'context> { } } - fn declare_numeric_generics(&mut self, params: &[Type], return_type: &Type) { + fn declare_numeric_generics(&mut self, params: &Parameters, return_type: &Type) { if self.generics.is_empty() { return; } @@ -717,11 +748,11 @@ impl<'context> Elaborator<'context> { } fn find_numeric_generics( - parameters: &[Type], + parameters: &Parameters, return_type: &Type, ) -> Vec<(String, TypeVariable)> { let mut found = BTreeMap::new(); - for parameter in parameters { + for (_, parameter, _) in ¶meters.0 { Self::find_numeric_generics_in_type(parameter, &mut found); } Self::find_numeric_generics_in_type(return_type, &mut found); @@ -835,33 +866,11 @@ impl<'context> Elaborator<'context> { module: LocalModuleId, impls: Vec<(Vec, Span, UnresolvedFunctions)>, ) { - self.generics.clear(); - for (generics, _, functions) in impls { self.file = functions.file_id; - self.add_generics(&generics); - let self_type = self.resolve_type(typ.clone()); - self.self_type = Some(self_type.clone()); - - let function_ids = vecmap(&functions.functions, |(_, id, _)| *id); + let old_generics_length = self.generics.len(); self.elaborate_functions(functions); - - if self_type != Type::Error { - for method_id in function_ids { - let method_name = self.interner.function_name(&method_id).to_owned(); - - if let Some(first_fn) = - self.interner.add_method(&self_type, method_name.clone(), method_id, false) - { - let error = ResolverError::DuplicateDefinition { - name: method_name, - first_span: self.interner.function_ident(&first_fn).span(), - second_span: self.interner.function_ident(&method_id).span(), - }; - self.push_err(error); - } - } - } + self.generics.truncate(old_generics_length); } } @@ -871,16 +880,18 @@ impl<'context> Elaborator<'context> { let unresolved_type = trait_impl.object_type; let self_type_span = unresolved_type.span; - self.add_generics(&trait_impl.generics); + let old_generics_length = self.generics.len(); + self.generics = trait_impl.resolved_generics; let trait_generics = vecmap(&trait_impl.trait_generics, |generic| self.resolve_type(generic.clone())); - let self_type = self.resolve_type(unresolved_type.clone()); - let impl_id = self.interner.next_trait_impl_id(); + let self_type = trait_impl.resolved_object_type.unwrap_or(Type::Error); + let impl_id = + trait_impl.impl_id.expect("An impls' id should be set during define_function_metas"); self.self_type = Some(self_type.clone()); - self.current_trait_impl = Some(impl_id); + self.current_trait_impl = trait_impl.impl_id; let mut methods = trait_impl.methods.function_ids(); @@ -937,20 +948,23 @@ impl<'context> Elaborator<'context> { self.self_type = None; self.current_trait_impl = None; - self.generics.clear(); + self.generics.truncate(old_generics_length); } fn collect_impls( &mut self, self_type: &UnresolvedType, module: LocalModuleId, - impls: &[(Vec, Span, UnresolvedFunctions)], + impls: &mut [(Vec, Span, UnresolvedFunctions)], ) { self.local_module = module; for (generics, span, unresolved) in impls { self.file = unresolved.file_id; - self.declare_method_on_struct(self_type, generics, false, unresolved, *span); + let old_generic_count = self.generics.len(); + self.add_generics(generics); + self.declare_methods_on_struct(self_type, false, unresolved, *span); + self.generics.truncate(old_generic_count); } } @@ -964,8 +978,11 @@ impl<'context> Elaborator<'context> { let span = trait_impl.object_type.span.expect("All trait self types should have spans"); let object_type = &trait_impl.object_type; - let generics = &trait_impl.generics; - self.declare_method_on_struct(object_type, generics, true, &trait_impl.methods, span); + let old_generic_count = self.generics.len(); + self.add_generics(&trait_impl.generics); + trait_impl.resolved_generics = self.generics.clone(); + self.declare_methods_on_struct(object_type, true, &mut trait_impl.methods, span); + self.generics.truncate(old_generic_count); } } @@ -974,33 +991,33 @@ impl<'context> Elaborator<'context> { &mut self.def_maps.get_mut(&module.krate).expect(message).modules[module.local_id.0] } - fn declare_method_on_struct( + fn declare_methods_on_struct( &mut self, self_type: &UnresolvedType, - generics: &UnresolvedGenerics, is_trait_impl: bool, - functions: &UnresolvedFunctions, + functions: &mut UnresolvedFunctions, span: Span, ) { - let generic_count = self.generics.len(); - self.add_generics(generics); - let typ = self.resolve_type(self_type.clone()); + let self_type = self.resolve_type(self_type.clone()); + + functions.self_type = Some(self_type.clone()); - if let Type::Struct(struct_type, _generics) = typ { - let struct_type = struct_type.borrow(); + let function_ids = functions.function_ids(); + + if let Type::Struct(struct_type, generics) = &self_type { + let struct_ref = struct_type.borrow(); // `impl`s are only allowed on types defined within the current crate - if !is_trait_impl && struct_type.id.krate() != self.crate_id { - let type_name = struct_type.name.to_string(); + if !is_trait_impl && struct_ref.id.krate() != self.crate_id { + let type_name = struct_ref.name.to_string(); self.push_err(DefCollectorErrorKind::ForeignImpl { span, type_name }); - self.generics.truncate(generic_count); return; } // Grab the module defined by the struct type. Note that impls are a case // where the module the methods are added to is not the same as the module // they are resolved in. - let module = self.get_module_mut(struct_type.id.module_id()); + let module = self.get_module_mut(struct_ref.id.module_id()); for (_, method_id, method) in &functions.functions { // If this method was already declared, remove it from the module so it cannot @@ -1012,11 +1029,33 @@ impl<'context> Elaborator<'context> { module.remove_function(method.name_ident()); } } - // Prohibit defining impls for primitive types if we're not in the stdlib - } else if !is_trait_impl && typ != Type::Error && !self.crate_id.is_stdlib() { - self.push_err(DefCollectorErrorKind::NonStructTypeInImpl { span }); + + self.declare_struct_methods(&self_type, &function_ids); + // We can define methods on primitive types only if we're in the stdlib + } else if !is_trait_impl && self_type != Type::Error { + if self.crate_id.is_stdlib() { + self.declare_struct_methods(&self_type, &function_ids); + } else { + self.push_err(DefCollectorErrorKind::NonStructTypeInImpl { span }); + } + } + } + + fn declare_struct_methods(&mut self, self_type: &Type, function_ids: &[FuncId]) { + for method_id in function_ids { + let method_name = self.interner.function_name(&method_id).to_owned(); + + if let Some(first_fn) = + self.interner.add_method(self_type, method_name.clone(), *method_id, false) + { + let error = ResolverError::DuplicateDefinition { + name: method_name, + first_span: self.interner.function_ident(&first_fn).span(), + second_span: self.interner.function_ident(&method_id).span(), + }; + self.push_err(error); + } } - self.generics.truncate(generic_count); } fn collect_trait_impl_methods( @@ -1229,4 +1268,61 @@ impl<'context> Elaborator<'context> { self.interner.get_global_definition_mut(global_id).kind = definition_kind; self.interner.replace_statement(statement_id, let_statement); } + + fn define_function_metas( + &mut self, + functions: &mut [UnresolvedFunctions], + impls: &mut ImplMap, + trait_impls: &mut [UnresolvedTraitImpl], + ) { + for function_set in functions { + self.define_function_metas_for_functions(function_set); + } + + for ((self_type, local_module), function_sets) in impls { + self.local_module = *local_module; + + for (generics, _, function_set) in function_sets { + self.add_generics(generics); + let self_type = self.resolve_type(self_type.clone()); + function_set.self_type = Some(self_type.clone()); + self.self_type = Some(self_type); + self.define_function_metas_for_functions(function_set); + } + } + + for trait_impl in trait_impls { + self.file = trait_impl.file_id; + self.local_module = trait_impl.module_id; + + let unresolved_type = &trait_impl.object_type; + let self_type_span = unresolved_type.span; + let old_generics_length = self.generics.len(); + self.add_generics(&trait_impl.generics); + + let self_type = self.resolve_type(unresolved_type.clone()); + self.self_type = Some(self_type.clone()); + trait_impl.methods.self_type = Some(self_type); + + let impl_id = self.interner.next_trait_impl_id(); + self.current_trait_impl = Some(impl_id); + + self.define_function_metas_for_functions(&mut trait_impl.methods); + + trait_impl.resolved_object_type = self.self_type.take(); + trait_impl.impl_id = self.current_trait_impl.take(); + self.generics.truncate(old_generics_length); + } + } + + fn define_function_metas_for_functions(&mut self, function_set: &mut UnresolvedFunctions) { + self.file = function_set.file_id; + + for (local_module, id, func) in &mut function_set.functions { + self.local_module = *local_module; + let old_generics_length = self.generics.len(); + self.define_function_meta(func, *id); + self.generics.truncate(old_generics_length); + } + } } diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index e7018d900d8..1f2b0d92229 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -26,10 +26,6 @@ use super::Elaborator; impl<'context> Elaborator<'context> { pub fn collect_traits(&mut self, traits: BTreeMap) { - for (trait_id, unresolved_trait) in &traits { - self.interner.push_empty_trait(*trait_id, unresolved_trait); - } - for (trait_id, unresolved_trait) in traits { let generics = vecmap(&unresolved_trait.trait_def.generics, |_| { TypeVariable::unbound(self.interner.next_type_variable_id()) @@ -187,7 +183,9 @@ impl<'context> Elaborator<'context> { return_visibility: Visibility::Private, }; - self.elaborate_function(NoirFunction { kind, def }, func_id); + let mut function = NoirFunction { kind, def }; + self.define_function_meta(&mut function, func_id); + self.elaborate_function(function, func_id); let _ = self.scopes.end_function(); // Don't check the scope tree for unused variables, they can't be used in a declaration anyway. self.trait_bounds.clear(); diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 3c8d805d802..cadf7dacf78 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -1204,6 +1204,10 @@ impl<'context> Elaborator<'context> { other => match self.interner.lookup_primitive_method(&other, method_name) { Some(method_id) => Some(HirMethodReference::FuncId(method_id)), None => { + panic!( + "Unresolved method call on other/primitive! {:?}::{}", + object_type, method_name + ); self.push_err(TypeCheckError::UnresolvedMethodCall { method_name: method_name.to_string(), object_type: object_type.clone(), diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index afec3839599..838aac3f067 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -5,6 +5,7 @@ use crate::graph::CrateId; use crate::hir::comptime::{Interpreter, InterpreterError}; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; use crate::hir::resolution::errors::ResolverError; +use crate::{Type, TypeVariable}; use crate::hir::resolution::import::{resolve_import, ImportDirective, PathResolution}; use crate::hir::resolution::{ @@ -18,7 +19,9 @@ use crate::hir::type_check::{ use crate::hir::Context; use crate::macros_api::{MacroError, MacroProcessor}; -use crate::node_interner::{FuncId, GlobalId, NodeInterner, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{ + FuncId, GlobalId, NodeInterner, StructId, TraitId, TraitImplId, TypeAliasId, +}; use crate::ast::{ ExpressionKind, Ident, LetStatement, Literal, NoirFunction, NoirStruct, NoirTrait, @@ -30,6 +33,7 @@ use iter_extended::vecmap; use noirc_errors::{CustomDiagnostic, Span}; use std::collections::{BTreeMap, HashMap}; +use std::rc::Rc; use std::vec; #[derive(Default)] @@ -47,6 +51,9 @@ pub struct UnresolvedFunctions { pub file_id: FileId, pub functions: Vec<(LocalModuleId, FuncId, NoirFunction)>, pub trait_id: Option, + + // The object type this set of functions was declared on, if there is one. + pub self_type: Option, } impl UnresolvedFunctions { @@ -107,13 +114,18 @@ pub struct UnresolvedTrait { pub struct UnresolvedTraitImpl { pub file_id: FileId, pub module_id: LocalModuleId, - pub trait_id: Option, pub trait_generics: Vec, pub trait_path: Path, pub object_type: UnresolvedType, pub methods: UnresolvedFunctions, pub generics: UnresolvedGenerics, pub where_clause: Vec, + + // These fields are filled in later + pub trait_id: Option, + pub impl_id: Option, + pub resolved_object_type: Option, + pub resolved_generics: Vec<(Rc, TypeVariable, Span)>, } #[derive(Clone)] @@ -337,7 +349,7 @@ impl DefCollector { if use_elaborator { let mut more_errors = Elaborator::elaborate(context, crate_id, def_collector.items); - more_errors.append(&mut errors); + errors.append(&mut more_errors); return errors; } diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 3d0ffdb0155..baea00ad23d 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -144,6 +144,7 @@ impl<'a> ModCollector<'a> { file_id: self.file_id, functions: Vec::new(), trait_id: None, + self_type: None, }; for (method, _) in r#impl.methods { @@ -187,8 +188,13 @@ impl<'a> ModCollector<'a> { object_type: trait_impl.object_type, generics: trait_impl.impl_generics, where_clause: trait_impl.where_clause, - trait_id: None, // will be filled later trait_generics: trait_impl.trait_generics, + + // These last fields are filled later on + trait_id: None, + impl_id: None, + resolved_object_type: None, + resolved_generics: Vec::new(), }; self.def_collector.items.trait_impls.push(unresolved_trait_impl); @@ -201,8 +207,12 @@ impl<'a> ModCollector<'a> { trait_impl: &NoirTraitImpl, krate: CrateId, ) -> UnresolvedFunctions { - let mut unresolved_functions = - UnresolvedFunctions { file_id: self.file_id, functions: Vec::new(), trait_id: None }; + let mut unresolved_functions = UnresolvedFunctions { + file_id: self.file_id, + functions: Vec::new(), + trait_id: None, + self_type: None, + }; let module = ModuleId { krate, local_id: self.module_id }; @@ -224,8 +234,12 @@ impl<'a> ModCollector<'a> { functions: Vec, krate: CrateId, ) -> Vec<(CompilationError, FileId)> { - let mut unresolved_functions = - UnresolvedFunctions { file_id: self.file_id, functions: Vec::new(), trait_id: None }; + let mut unresolved_functions = UnresolvedFunctions { + file_id: self.file_id, + functions: Vec::new(), + trait_id: None, + self_type: None, + }; let mut errors = vec![]; let module = ModuleId { krate, local_id: self.module_id }; @@ -398,6 +412,7 @@ impl<'a> ModCollector<'a> { file_id: self.file_id, functions: Vec::new(), trait_id: None, + self_type: None, }; let mut method_ids = HashMap::new(); @@ -507,6 +522,7 @@ impl<'a> ModCollector<'a> { method_ids, fns_with_default_impl: unresolved_functions, }; + context.def_interner.push_empty_trait(trait_id, &unresolved); self.def_collector.items.traits.insert(trait_id, unresolved); } errors diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 1f006697359..a982cd1b611 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1104,6 +1104,9 @@ impl<'a> Resolver<'a> { trait_constraints: self.resolve_trait_constraints(&func.def.where_clause), is_entry_point: self.is_entry_point_function(func), has_inline_attribute, + + // This is only used by the elaborator + all_generics: Vec::new(), } } diff --git a/compiler/noirc_frontend/src/hir_def/function.rs b/compiler/noirc_frontend/src/hir_def/function.rs index ceec9ad8580..dcfded2912f 100644 --- a/compiler/noirc_frontend/src/hir_def/function.rs +++ b/compiler/noirc_frontend/src/hir_def/function.rs @@ -109,6 +109,12 @@ pub struct FuncMeta { /// such as a trait's `Self` type variable. pub direct_generics: Vec<(Rc, TypeVariable)>, + /// All the generics used by this function, which includes any implicit generics or generics + /// from outer scopes, such as those introduced by an impl. + /// This is stored when the FuncMeta is first created to later be used to set the current + /// generics when the function's body is later resolved. + pub all_generics: Vec<(Rc, TypeVariable, Span)>, + pub location: Location, // This flag is needed for the attribute check pass diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index d4145ef6a1d..60cc2580bb8 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -111,7 +111,9 @@ pub struct NodeInterner { // The purpose for this hashmap is to detect duplication of trait implementations ( if any ) // // Indexed by TraitImplIds - pub(crate) trait_implementations: Vec>, + pub(crate) trait_implementations: HashMap>, + + next_trait_implementation_id: usize, /// Trait implementations on each type. This is expected to always have the same length as /// `self.trait_implementations`. @@ -485,7 +487,8 @@ impl Default for NodeInterner { struct_attributes: HashMap::new(), type_aliases: Vec::new(), traits: HashMap::new(), - trait_implementations: Vec::new(), + trait_implementations: HashMap::new(), + next_trait_implementation_id: 0, trait_implementation_map: HashMap::new(), selected_trait_implementations: HashMap::new(), operator_traits: HashMap::new(), @@ -1143,7 +1146,7 @@ impl NodeInterner { } pub fn get_trait_implementation(&self, id: TraitImplId) -> Shared { - self.trait_implementations[id.0].clone() + self.trait_implementations[&id].clone() } /// Given a `ObjectType: TraitId` pair, try to find an existing impl that satisfies the @@ -1378,9 +1381,7 @@ impl NodeInterner { impl_generics: Generics, trait_impl: Shared, ) -> Result<(), (Span, FileId)> { - assert_eq!(impl_id.0, self.trait_implementations.len(), "trait impl defined out of order"); - - self.trait_implementations.push(trait_impl.clone()); + self.trait_implementations.insert(impl_id, trait_impl.clone()); // Replace each generic with a fresh type variable let substitutions = impl_generics @@ -1483,10 +1484,10 @@ impl NodeInterner { } /// Returns what the next trait impl id is expected to be. - /// Note that this does not actually reserve the slot so care should - /// be taken that the next trait impl added matches this ID. - pub fn next_trait_impl_id(&self) -> TraitImplId { - TraitImplId(self.trait_implementations.len()) + pub fn next_trait_impl_id(&mut self) -> TraitImplId { + let next_id = self.next_trait_implementation_id; + self.next_trait_implementation_id += 1; + TraitImplId(next_id) } /// Removes all TraitImplKind::Assumed from the list of known impls for the given trait diff --git a/compiler/noirc_frontend/src/resolve_locations.rs b/compiler/noirc_frontend/src/resolve_locations.rs index 2fa7c8adbf8..5efe2e4a041 100644 --- a/compiler/noirc_frontend/src/resolve_locations.rs +++ b/compiler/noirc_frontend/src/resolve_locations.rs @@ -157,11 +157,11 @@ impl NodeInterner { self.trait_implementations .iter() .find(|shared_trait_impl| { - let trait_impl = shared_trait_impl.borrow(); + let trait_impl = shared_trait_impl.1.borrow(); trait_impl.file == location.file && trait_impl.ident.span().contains(&location.span) }) .and_then(|shared_trait_impl| { - let trait_impl = shared_trait_impl.borrow(); + let trait_impl = shared_trait_impl.1.borrow(); self.traits.get(&trait_impl.trait_id).map(|trait_| trait_.location) }) } diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index 6c0709e7611..7c50e907dc9 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -102,7 +102,8 @@ pub(crate) fn run(args: InfoCommand, config: NargoConfig) -> Result<(), CliError } else { // Otherwise print human-readable table. if !info_report.programs.is_empty() { - let mut program_table = table!([Fm->"Package", Fm->"Function", Fm->"Expression Width", Fm->"ACIR Opcodes"]); + let mut program_table = + table!([Fm->"Package", Fm->"Function", Fm->"Expression Width", Fm->"ACIR Opcodes"]); for program_info in info_report.programs { let program_rows: Vec = program_info.into();