diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index a0ff3c12ae3..b96f5e02c8b 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -15,7 +15,7 @@ use crate::{ }, resolution::{errors::ResolverError, path_resolver::PathResolver, resolver::LambdaContext}, scope::ScopeForest as GenericScopeForest, - type_check::TypeCheckError, + type_check::{check_trait_impl_method_matches_declaration, TypeCheckError}, }, hir_def::{expr::HirIdent, function::Parameters, traits::TraitConstraint}, macros_api::{ @@ -851,6 +851,12 @@ impl<'context> Elaborator<'context> { self.generics = trait_impl.resolved_generics; self.current_trait_impl = trait_impl.impl_id; + for (module, function, _) in &trait_impl.methods.functions { + self.local_module = *module; + let errors = check_trait_impl_method_matches_declaration(self.interner, *function); + self.errors.extend(errors.into_iter().map(|error| (error.into(), self.file))); + } + self.elaborate_functions(trait_impl.methods); self.self_type = None; @@ -877,12 +883,14 @@ impl<'context> Elaborator<'context> { fn collect_trait_impl(&mut self, trait_impl: &mut UnresolvedTraitImpl) { self.local_module = trait_impl.module_id; self.file = trait_impl.file_id; + self.current_trait_impl = trait_impl.impl_id; trait_impl.trait_id = self.resolve_trait_by_path(trait_impl.trait_path.clone()); let self_type = trait_impl.methods.self_type.clone(); let self_type = self_type.expect("Expected struct type to be set before collect_trait_impl"); + self.self_type = Some(self_type.clone()); let self_type_span = trait_impl.object_type.span; if matches!(self_type, Type::MutableReference(_)) { @@ -890,12 +898,11 @@ impl<'context> Elaborator<'context> { self.push_err(DefCollectorErrorKind::MutableReferenceInTraitImpl { span }); } - assert!(trait_impl.trait_id.is_some()); if let Some(trait_id) = trait_impl.trait_id { + self.generics = trait_impl.resolved_generics.clone(); self.collect_trait_impl_methods(trait_id, trait_impl); let span = trait_impl.object_type.span.expect("All trait self types should have spans"); - self.generics = trait_impl.resolved_generics.clone(); self.declare_methods_on_struct(true, &mut trait_impl.methods, span); let methods = trait_impl.methods.function_ids(); @@ -945,6 +952,8 @@ impl<'context> Elaborator<'context> { } self.generics.clear(); + self.current_trait_impl = None; + self.self_type = None; } fn get_module_mut(&mut self, module: ModuleId) -> &mut ModuleData { @@ -1059,6 +1068,7 @@ impl<'context> Elaborator<'context> { let module = self.module_id(); let location = Location::new(default_impl.def.span, trait_impl.file_id); self.interner.push_function(func_id, &default_impl.def, module, location); + self.define_function_meta(&mut default_impl_clone, func_id, false); func_ids_in_trait.insert(func_id); ordered_methods.push(( method.default_impl_module_id, diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index de2e575b4e2..65a3186b004 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -237,7 +237,13 @@ pub(crate) fn check_trait_impl_method_matches_declaration( let impl_ = meta.trait_impl.expect("Trait impl function should have a corresponding trait impl"); - let impl_ = interner.get_trait_implementation(impl_); + + // If the trait implementation is not defined in the interner then there was a previous + // error in resolving the trait path and there is likely no trait for this impl. + let Some(impl_) = interner.try_get_trait_implementation(impl_) else { + return errors; + }; + let impl_ = impl_.borrow(); let trait_info = interner.get_trait(impl_.trait_id); diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 60cc2580bb8..e28a0a64ad0 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -1145,6 +1145,10 @@ impl NodeInterner { } } + pub fn try_get_trait_implementation(&self, id: TraitImplId) -> Option> { + self.trait_implementations.get(&id).cloned() + } + pub fn get_trait_implementation(&self, id: TraitImplId) -> Shared { self.trait_implementations[&id].clone() } diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index bd81752c046..99215c8f173 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -494,7 +494,10 @@ fn check_trait_wrong_parameter_type() { }"; let errors = get_program_errors(src); assert!(!has_parser_error(&errors)); - assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); + + // This is a duplicate error in the name resolver & type checker. + // In the elaborator there is no duplicate and only 1 error is issued + assert!(errors.len() <= 2, "Expected 1 or 2 errors, got: {:?}", errors); for (err, _file_id) in errors { match &err { @@ -593,22 +596,20 @@ fn check_impl_struct_not_trait() { bar: Field, array: [Field; 2], } - + struct Default { x: Field, z: Field, } - // Default is struct not a trait + // Default is a struct not a trait impl Default for Foo { fn default(x: Field, y: Field) -> Self { Self { bar: x, array: [x,y] } } } - fn main() { - } - + fn main() {} "; let errors = get_program_errors(src); assert!(!has_parser_error(&errors));