From 2cbd950ad187e19a250fda913dac3bccc1d80980 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Wed, 8 Jan 2025 15:26:58 -0300 Subject: [PATCH 1/3] fix: return trait impl method as FuncId if there's only one --- compiler/noirc_frontend/src/elaborator/types.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 320b85e70c..5c6002ec32 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -1426,7 +1426,7 @@ impl<'context> Elaborator<'context> { // Only keep unique trait IDs: multiple trait methods might come from the same trait // but implemented with different generics (like `Convert` and `Convert`). let traits: HashSet = - trait_methods.into_iter().map(|(_, trait_id)| trait_id).collect(); + trait_methods.iter().map(|(_, trait_id)| *trait_id).collect(); let traits_in_scope: Vec<_> = traits .iter() @@ -1491,6 +1491,12 @@ impl<'context> Elaborator<'context> { return None; } + // If we find a single trait impl method, return it so we don't have to determine the impl + if trait_methods.len() == 1 { + let (func_id, _) = trait_methods[0]; + return Some(HirMethodReference::FuncId(func_id)); + } + // Return a TraitMethodId with unbound generics. These will later be bound by the type-checker. let trait_id = traits_in_scope[0].0; let trait_ = self.interner.get_trait(trait_id); From babc3d804cbdbe3eedf5dd3c72c82dc316327543 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Wed, 8 Jan 2025 15:37:59 -0300 Subject: [PATCH 2/3] Same workaround if the trait isn't in scope --- compiler/noirc_frontend/src/elaborator/types.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 5c6002ec32..9d0107dab7 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -1465,6 +1465,12 @@ impl<'context> Elaborator<'context> { trait_name, }); + // If we find a single trait impl method, return it so we don't have to determine the impl + if trait_methods.len() == 1 { + let (func_id, _) = trait_methods[0]; + return Some(HirMethodReference::FuncId(func_id)); + } + return Some(HirMethodReference::TraitMethodId(trait_method_id, generics, false)); } else { let traits = vecmap(traits, |trait_id| { From dc74d68e83245ae2b249f2ff5cfe41ba0d5f94a5 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Wed, 8 Jan 2025 15:41:36 -0300 Subject: [PATCH 3/3] Refactor to avoid code duplication --- .../noirc_frontend/src/elaborator/types.rs | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 9d0107dab7..0e26d0b5bd 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -30,7 +30,7 @@ use crate::{ traits::{NamedType, ResolvedTraitBound, Trait, TraitConstraint}, }, node_interner::{ - DependencyId, ExprId, GlobalValue, ImplSearchErrorKind, NodeInterner, TraitId, + DependencyId, ExprId, FuncId, GlobalValue, ImplSearchErrorKind, NodeInterner, TraitId, TraitImplKind, TraitMethodId, }, token::SecondaryAttribute, @@ -1457,21 +1457,18 @@ impl<'context> Elaborator<'context> { let trait_id = *traits.iter().next().unwrap(); let trait_ = self.interner.get_trait(trait_id); let trait_name = self.fully_qualified_trait_path(trait_); - let generics = trait_.as_constraint(span).trait_bound.trait_generics; - let trait_method_id = trait_.find_method(method_name).unwrap(); self.push_err(PathResolutionError::TraitMethodNotInScope { ident: Ident::new(method_name.into(), span), trait_name, }); - // If we find a single trait impl method, return it so we don't have to determine the impl - if trait_methods.len() == 1 { - let (func_id, _) = trait_methods[0]; - return Some(HirMethodReference::FuncId(func_id)); - } - - return Some(HirMethodReference::TraitMethodId(trait_method_id, generics, false)); + return Some(self.trait_hir_method_reference( + trait_id, + trait_methods, + method_name, + span, + )); } else { let traits = vecmap(traits, |trait_id| { let trait_ = self.interner.get_trait(trait_id); @@ -1497,18 +1494,28 @@ impl<'context> Elaborator<'context> { return None; } - // If we find a single trait impl method, return it so we don't have to determine the impl + let trait_id = traits_in_scope[0].0; + Some(self.trait_hir_method_reference(trait_id, trait_methods, method_name, span)) + } + + fn trait_hir_method_reference( + &self, + trait_id: TraitId, + trait_methods: Vec<(FuncId, TraitId)>, + method_name: &str, + span: Span, + ) -> HirMethodReference { + // If we find a single trait impl method, return it so we don't have to later determine the impl if trait_methods.len() == 1 { let (func_id, _) = trait_methods[0]; - return Some(HirMethodReference::FuncId(func_id)); + return HirMethodReference::FuncId(func_id); } // Return a TraitMethodId with unbound generics. These will later be bound by the type-checker. - let trait_id = traits_in_scope[0].0; let trait_ = self.interner.get_trait(trait_id); let generics = trait_.as_constraint(span).trait_bound.trait_generics; let trait_method_id = trait_.find_method(method_name).unwrap(); - Some(HirMethodReference::TraitMethodId(trait_method_id, generics, false)) + HirMethodReference::TraitMethodId(trait_method_id, generics, false) } fn lookup_method_in_trait_constraints(