diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index c581ea9d62a..7b0a6d028de 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -802,6 +802,7 @@ impl Display for TypePath { impl FunctionDefinition { pub fn normal( name: &Ident, + is_unconstrained: bool, generics: &UnresolvedGenerics, parameters: &[(Ident, UnresolvedType)], body: &BlockExpression, @@ -821,7 +822,7 @@ impl FunctionDefinition { FunctionDefinition { name: name.clone(), attributes: Attributes::empty(), - is_unconstrained: false, + is_unconstrained, is_comptime: false, visibility: ItemVisibility::Private, generics: generics.clone(), diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index 0faaf409e6c..d7c8769620d 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -11,10 +11,9 @@ use crate::{ hir_def::{function::Parameters, traits::TraitFunction}, macros_api::{ BlockExpression, FunctionDefinition, FunctionReturnType, Ident, ItemVisibility, - NodeInterner, NoirFunction, Param, Pattern, UnresolvedType, Visibility, + NodeInterner, NoirFunction, UnresolvedType, }, node_interner::{FuncId, ReferenceId, TraitId}, - token::Attributes, Kind, ResolvedGeneric, Type, TypeBindings, TypeVariableKind, }; @@ -103,6 +102,7 @@ impl<'context> Elaborator<'context> { this.resolve_trait_function( trait_id, name, + *is_unconstrained, generics, parameters, return_type, @@ -164,6 +164,7 @@ impl<'context> Elaborator<'context> { &mut self, trait_id: TraitId, name: &Ident, + is_unconstrained: bool, generics: &UnresolvedGenerics, parameters: &[(Ident, UnresolvedType)], return_type: &FunctionReturnType, @@ -175,25 +176,17 @@ impl<'context> Elaborator<'context> { self.scopes.start_function(); let kind = FunctionKind::Normal; - let def = FunctionDefinition { - name: name.clone(), - attributes: Attributes::empty(), - is_unconstrained: false, - is_comptime: false, - visibility: ItemVisibility::Public, // Trait functions are always public - generics: generics.clone(), - parameters: vecmap(parameters, |(name, typ)| Param { - visibility: Visibility::Private, - pattern: Pattern::Identifier(name.clone()), - typ: typ.clone(), - span: name.span(), - }), - body: BlockExpression { statements: Vec::new() }, - span: name.span(), - where_clause: where_clause.to_vec(), - return_type: return_type.clone(), - return_visibility: Visibility::Private, - }; + let mut def = FunctionDefinition::normal( + name, + is_unconstrained, + generics, + parameters, + &BlockExpression { statements: Vec::new() }, + where_clause, + return_type, + ); + // Trait functions are always public + def.visibility = ItemVisibility::Public; let mut function = NoirFunction { kind, def }; self.define_function_meta(&mut function, func_id, Some(trait_id)); 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 6e11b884c3f..f50a0608fab 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -466,6 +466,7 @@ impl<'a> ModCollector<'a> { let impl_method = NoirFunction::normal(FunctionDefinition::normal( name, + *is_unconstrained, generics, parameters, body, diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 33ab82bca2a..91e4115ff69 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -3046,9 +3046,7 @@ fn errors_once_on_unused_import_that_is_not_accessible() { mod moo { struct Foo {} } - use moo::Foo; - fn main() {} "#; @@ -3061,3 +3059,32 @@ fn errors_once_on_unused_import_that_is_not_accessible() { )) )); } + +#[test] +fn trait_unconstrained_methods_typechecked_correctly() { + // This test checks that we properly track whether a method has been declared as unconstrained on the trait definition + // and preserves that through typechecking. + let src = r#" + trait Foo { + unconstrained fn identity(self) -> Self { + self + } + + unconstrained fn foo(self) -> u64; + } + + impl Foo for Field { + unconstrained fn foo(self) -> u64 { + self as u64 + } + } + + unconstrained fn main() { + assert_eq(2.foo() as Field, 2.identity()); + } + "#; + + let errors = get_program_errors(src); + println!("{errors:?}"); + assert_eq!(errors.len(), 0); +}