Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: allow providing default implementations of unconstrained trait methods #6138

Merged
merged 11 commits into from
Sep 24, 2024
3 changes: 2 additions & 1 deletion compiler/noirc_frontend/src/ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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(),
Expand Down
35 changes: 14 additions & 21 deletions compiler/noirc_frontend/src/elaborator/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -103,6 +102,7 @@ impl<'context> Elaborator<'context> {
this.resolve_trait_function(
trait_id,
name,
*is_unconstrained,
generics,
parameters,
return_type,
Expand Down Expand Up @@ -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,
Expand All @@ -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));
Expand Down
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@
let impl_method =
NoirFunction::normal(FunctionDefinition::normal(
name,
*is_unconstrained,
generics,
parameters,
body,
Expand Down Expand Up @@ -799,7 +800,7 @@
// if it's an inline module, or the first char of a the file if it's an external module.
// - `location` will always point to the token "foo" in `mod foo` regardless of whether
// it's inline or external.
// Eventually the location put in `ModuleData` is used for codelenses about `contract`s,

Check warning on line 803 in compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (codelenses)
// so we keep using `location` so that it continues to work as usual.
let location = Location::new(mod_name.span(), mod_location.file);
let new_module =
Expand Down
31 changes: 29 additions & 2 deletions compiler/noirc_frontend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2945,7 +2945,7 @@
}

#[test]
fn arithmetic_generics_canonicalization_deduplication_regression() {

Check warning on line 2948 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (canonicalization)
let source = r#"
struct ArrData<let N: u32> {
a: [Field; N],
Expand Down Expand Up @@ -3046,9 +3046,7 @@
mod moo {
struct Foo {}
}

use moo::Foo;

fn main() {}
"#;

Expand All @@ -3061,3 +3059,32 @@
))
));
}

#[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);
}
Loading