Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
ast::{IdentOrQuotedType, ItemVisibility, UnresolvedType},
graph::CrateGraph,
hir::def_collector::dc_crate::UnresolvedTrait,
hir_def::traits::ResolvedTraitBound,
hir_def::traits::{NamedType, ResolvedTraitBound},
node_interner::{GlobalValue, QuotedTypeId},
token::SecondaryAttributeKind,
usage_tracker::UsageTracker,
Expand Down Expand Up @@ -1392,22 +1392,37 @@ impl<'context> Elaborator<'context> {
else {
continue;
};
let trait_constraint_trait_name = trait_constraint_trait.name.to_string();

let trait_constraint_type = trait_constraint.typ.substitute(&bindings);
let trait_bound = &trait_constraint.trait_bound;

let mut named_generics = trait_bound.trait_generics.named.clone();

// If the trait bound is over a trait that has associated types, the ones that
// aren't explicit will be in `named_generics` as implicitly added ones.
// If they are unbound, they won't be bound until monomorphization, in which cae
// the below trait implementation lookup will fail (an unbound named generic will
// never unify in this case). In this case we replace them with fresh type variables
// so they'll unify (the bindings aren't applied here so this is fine).
// If they are bound though, we won't replace them as we want to ensure the binding
// matches.
self.replace_implicitly_added_unbound_named_generics_with_fresh_type_variables(
&mut named_generics,
);

if self
.interner
.try_lookup_trait_implementation(
&trait_constraint_type,
trait_bound.trait_id,
&trait_bound.trait_generics.ordered,
&trait_bound.trait_generics.named,
&named_generics,
)
.is_err()
{
let missing_trait =
format!("{}{}", trait_constraint_trait.name, trait_bound.trait_generics);
format!("{}{}", trait_constraint_trait_name, trait_bound.trait_generics);
self.push_err(ResolverError::TraitNotImplemented {
impl_trait: impl_trait.clone(),
missing_trait,
Expand All @@ -1419,6 +1434,22 @@ impl<'context> Elaborator<'context> {
}
}

fn replace_implicitly_added_unbound_named_generics_with_fresh_type_variables(
&mut self,
named_generics: &mut [NamedType],
) {
for named_type in named_generics.iter_mut() {
match &named_type.typ {
Type::NamedGeneric(NamedGeneric { type_var, implicit: true, .. })
if type_var.borrow().is_unbound() =>
{
named_type.typ = self.interner.next_type_variable();
}
_ => (),
};
}
}

fn check_parent_traits_are_implemented(&mut self, trait_impl: &UnresolvedTraitImpl) {
let Some(trait_id) = trait_impl.trait_id else {
return;
Expand Down
24 changes: 24 additions & 0 deletions compiler/noirc_frontend/src/tests/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2022,6 +2022,30 @@ fn associated_constant_mul_of_other_constants() {
assert_no_errors!(src);
}

#[named]
#[test]
fn trait_bound_with_associated_constant() {
let src = r#"
pub trait Other {
let N: u32;
}

pub trait Trait<T>
where
T: Other,
{}

impl Other for Field {
let N: u32 = 1;
}

impl Trait<Field> for i32 {}

fn main() {}
"#;
assert_no_errors!(src);
}

#[named]
#[test]
fn trait_method_call_when_it_has_bounds_on_generic() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

[package]
name = "noirc_frontend_tests_traits_trait_bound_with_associated_constant"
type = "bin"
authors = [""]

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

pub trait Other {
let N: u32;
}

pub trait Trait<T>
where
T: Other,
{}

impl Other for Field {
let N: u32 = 1;
}

impl Trait<Field> for i32 {}

fn main() {}

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1955914972083164529

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading