diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index 66ed9c8acce..9263fe9c67d 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -229,6 +229,7 @@ pub(crate) fn check_trait_impl_method_matches_declaration( function: FuncId, ) -> Vec { let meta = interner.function_meta(&function); + let modifiers = interner.function_modifiers(&function); let method_name = interner.function_name(&function); let mut errors = Vec::new(); @@ -267,6 +268,14 @@ pub(crate) fn check_trait_impl_method_matches_declaration( // issue an error for it here. if let Some(trait_fn_id) = trait_info.method_ids.get(method_name) { let trait_fn_meta = interner.function_meta(trait_fn_id); + let trait_fn_modifiers = interner.function_modifiers(trait_fn_id); + + if modifiers.is_unconstrained != trait_fn_modifiers.is_unconstrained { + let expected = trait_fn_modifiers.is_unconstrained; + let span = meta.name.location.span; + let item = method_name.to_string(); + errors.push(TypeCheckError::UnconstrainedMismatch { item, expected, span }); + } if trait_fn_meta.direct_generics.len() != meta.direct_generics.len() { let expected = trait_fn_meta.direct_generics.len(); diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index 626084ce1b6..155564536d6 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -61,6 +61,8 @@ pub enum TypeCheckError { ParameterCountMismatch { expected: usize, found: usize, span: Span }, #[error("{item} expects {expected} generics but {found} were given")] GenericCountMismatch { item: String, expected: usize, found: usize, span: Span }, + #[error("{item} has incompatible `unconstrained`")] + UnconstrainedMismatch { item: String, expected: bool, span: Span }, #[error("Only integer and Field types may be casted to")] UnsupportedCast { span: Span }, #[error("Index {index} is out of bounds for this tuple {lhs_type} of length {length}")] @@ -264,6 +266,14 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic { let msg = format!("{item} expects {expected} generic{empty_or_s} but {found} {was_or_were} given"); Diagnostic::simple_error(msg, String::new(), *span) } + TypeCheckError::UnconstrainedMismatch { item, expected, span } => { + let msg = if *expected { + format!("{item} is expected to be unconstrained") + } else { + format!("{item} is not expected to be unconstrained") + }; + Diagnostic::simple_error(msg, String::new(), *span) + } TypeCheckError::InvalidCast { span, .. } | TypeCheckError::ExpectedFunction { span, .. } | TypeCheckError::AccessUnknownMember { span, .. } diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index aa07972ae5d..75fe1bf747f 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -45,8 +45,8 @@ pub enum ParserErrorReason { PatternInTraitFunctionParameter, #[error("Patterns aren't allowed in a trait impl's associated constants")] PatternInAssociatedConstant, - #[error("Modifiers are ignored on a trait impl method")] - TraitImplFunctionModifiers, + #[error("Visibility is ignored on a trait impl method")] + TraitImplVisibilityIgnored, #[error("comptime keyword is deprecated")] ComptimeDeprecated, #[error("{0} are experimental and aren't fully supported yet")] @@ -202,7 +202,7 @@ impl<'a> From<&'a ParserError> for Diagnostic { ParserErrorReason::ExperimentalFeature(_) => { Diagnostic::simple_warning(reason.to_string(), "".into(), error.span) } - ParserErrorReason::TraitImplFunctionModifiers => { + ParserErrorReason::TraitImplVisibilityIgnored => { Diagnostic::simple_warning(reason.to_string(), "".into(), error.span) } ParserErrorReason::ExpectedPatternButFoundType(ty) => Diagnostic::simple_error( diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index 77c6e87a842..b95319f6da0 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -187,8 +187,8 @@ pub(super) fn trait_implementation() -> impl NoirParser { fn trait_implementation_body() -> impl NoirParser>> { let function = function::function_definition(true).validate(|mut f, span, emit| { - if f.def().is_unconstrained || f.def().visibility != ItemVisibility::Private { - emit(ParserError::with_reason(ParserErrorReason::TraitImplFunctionModifiers, span)); + if f.def().visibility != ItemVisibility::Private { + emit(ParserError::with_reason(ParserErrorReason::TraitImplVisibilityIgnored, span)); } // Trait impl functions are always public f.def_mut().visibility = ItemVisibility::Public; diff --git a/tooling/lsp/src/requests/code_action/implement_missing_members.rs b/tooling/lsp/src/requests/code_action/implement_missing_members.rs index b2d052b54f7..1cd181966a2 100644 --- a/tooling/lsp/src/requests/code_action/implement_missing_members.rs +++ b/tooling/lsp/src/requests/code_action/implement_missing_members.rs @@ -101,10 +101,12 @@ impl<'a> CodeActionFinder<'a> { for (name, func_id) in method_ids { let func_meta = self.interner.function_meta(func_id); + let modifiers = self.interner.function_modifiers(func_id); let mut generator = TraitImplMethodStubGenerator::new( name, func_meta, + modifiers, trait_, noir_trait_impl, self.interner, diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index b85ab483860..a957d88fd3b 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -899,10 +899,12 @@ impl<'a> NodeFinder<'a> { } let func_meta = self.interner.function_meta(&func_id); + let modifiers = self.interner.function_modifiers(&func_id); let mut generator = TraitImplMethodStubGenerator::new( &name, func_meta, + modifiers, trait_, noir_trait_impl, self.interner, diff --git a/tooling/lsp/src/trait_impl_method_stub_generator.rs b/tooling/lsp/src/trait_impl_method_stub_generator.rs index e4c22f1790c..f80bdf000b0 100644 --- a/tooling/lsp/src/trait_impl_method_stub_generator.rs +++ b/tooling/lsp/src/trait_impl_method_stub_generator.rs @@ -9,7 +9,7 @@ use noirc_frontend::{ }, hir_def::{function::FuncMeta, stmt::HirPattern, traits::Trait}, macros_api::{ModuleDefId, NodeInterner}, - node_interner::ReferenceId, + node_interner::{FunctionModifiers, ReferenceId}, Kind, ResolvedGeneric, Type, TypeVariableKind, }; @@ -18,6 +18,7 @@ use crate::modules::relative_module_id_path; pub(crate) struct TraitImplMethodStubGenerator<'a> { name: &'a str, func_meta: &'a FuncMeta, + modifiers: &'a FunctionModifiers, trait_: &'a Trait, noir_trait_impl: &'a NoirTraitImpl, interner: &'a NodeInterner, @@ -33,6 +34,7 @@ impl<'a> TraitImplMethodStubGenerator<'a> { pub(crate) fn new( name: &'a str, func_meta: &'a FuncMeta, + modifiers: &'a FunctionModifiers, trait_: &'a Trait, noir_trait_impl: &'a NoirTraitImpl, interner: &'a NodeInterner, @@ -43,6 +45,7 @@ impl<'a> TraitImplMethodStubGenerator<'a> { Self { name, func_meta, + modifiers, trait_, noir_trait_impl, interner, @@ -63,6 +66,9 @@ impl<'a> TraitImplMethodStubGenerator<'a> { let indent_string = " ".repeat(self.indent); self.string.push_str(&indent_string); + if self.modifiers.is_unconstrained { + self.string.push_str("unconstrained "); + } self.string.push_str("fn "); self.string.push_str(self.name); self.append_resolved_generics(&self.func_meta.direct_generics);