Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
104 changes: 51 additions & 53 deletions compiler/noirc_frontend/src/node_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1648,29 +1648,11 @@ impl NodeInterner {

let mut fresh_bindings = type_bindings.clone();

let mut check_trait_generics =
|impl_generics: &[Type], impl_associated_types: &[NamedType]| {
let generics_unify = trait_generics.iter().zip(impl_generics).all(
|(trait_generic, impl_generic)| {
let impl_generic =
impl_generic.force_substitute(&instantiation_bindings);
trait_generic.try_unify(&impl_generic, &mut fresh_bindings).is_ok()
},
);

let associated_types_unify = trait_associated_types
.iter()
.zip(impl_associated_types)
.all(|(trait_generic, impl_generic)| {
let impl_generic2 =
impl_generic.typ.force_substitute(&instantiation_bindings);
trait_generic.typ.try_unify(&impl_generic2, &mut fresh_bindings).is_ok()
});

generics_unify && associated_types_unify
};
if object_type.try_unify(&existing_object_type, &mut fresh_bindings).is_err() {
continue;
}

let trait_generics = match impl_kind {
let impl_trait_generics = match impl_kind {
TraitImplKind::Normal(id) => {
let shared_impl = self.get_trait_implementation(*id);
let shared_impl = shared_impl.borrow();
Expand All @@ -1681,44 +1663,60 @@ impl NodeInterner {
TraitImplKind::Assumed { trait_generics, .. } => trait_generics.clone(),
};

if !check_trait_generics(&trait_generics.ordered, &trait_generics.named) {
let generics_unify = trait_generics.iter().zip(&impl_trait_generics.ordered).all(
|(trait_generic, impl_generic)| {
let impl_generic = impl_generic.force_substitute(&instantiation_bindings);
trait_generic.try_unify(&impl_generic, &mut fresh_bindings).is_ok()
},
);

if !generics_unify {
continue;
}

if object_type.try_unify(&existing_object_type, &mut fresh_bindings).is_ok() {
if let TraitImplKind::Normal(impl_id) = impl_kind {
let trait_impl = self.get_trait_implementation(*impl_id);
let trait_impl = trait_impl.borrow();

if let Err(error) = self.validate_where_clause(
&trait_impl.where_clause,
&mut fresh_bindings,
&instantiation_bindings,
recursion_limit,
) {
// Only keep the first errors we get from a failing where clause
if where_clause_error.is_none() {
where_clause_error = Some(error);
}
continue;
if let TraitImplKind::Normal(impl_id) = impl_kind {
let trait_impl = self.get_trait_implementation(*impl_id);
let trait_impl = trait_impl.borrow();

if let Err(error) = self.validate_where_clause(
&trait_impl.where_clause,
&mut fresh_bindings,
&instantiation_bindings,
recursion_limit,
) {
// Only keep the first errors we get from a failing where clause
if where_clause_error.is_none() {
where_clause_error = Some(error);
}
continue;
}
}

let constraint = TraitConstraint {
typ: existing_object_type,
trait_bound: ResolvedTraitBound {
trait_id,
trait_generics,
location: Location::dummy(),
},
};
matching_impls.push((
impl_kind.clone(),
fresh_bindings,
instantiation_bindings,
constraint,
));
let associated_types_unify = trait_associated_types
.iter()
.zip(&impl_trait_generics.named)
.all(|(trait_generic, impl_generic)| {
let impl_generic2 = impl_generic.typ.force_substitute(&instantiation_bindings);
trait_generic.typ.try_unify(&impl_generic2, &mut fresh_bindings).is_ok()
});
if !associated_types_unify {
continue;
}

let constraint = TraitConstraint {
typ: existing_object_type,
trait_bound: ResolvedTraitBound {
trait_id,
trait_generics: impl_trait_generics,
location: Location::dummy(),
},
};
matching_impls.push((
impl_kind.clone(),
fresh_bindings,
instantiation_bindings,
constraint,
));
}

if matching_impls.len() == 1 {
Expand Down
58 changes: 58 additions & 0 deletions compiler/noirc_frontend/src/tests/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1858,3 +1858,61 @@ fn suggests_importing_trait_via_module_reexport() {
"#;
check_errors!(src);
}

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

fn deserialize(_: [Field; Self::N]);
}

impl Deserialize for Field {
let N: u32 = 1;

fn deserialize(_: [Field; Self::N]) {}
}

struct Gen<T> {}

impl<T> Deserialize for Gen<T>
where
T: Deserialize,
{
let N: u32 = <T as Deserialize>::N + <T as Deserialize>::N;

fn deserialize(_: [Field; Self::N]) {}
}

fn main() {
let f = <Gen<Field> as Deserialize>::deserialize;
f([0; 2]);
}
"#;
assert_no_errors!(src);
}

#[named]
#[test]
fn regression_9245_small_code() {
let src = r#"
pub trait From2<T> {}

impl<T> From2<T> for T {}

pub trait Into2<T> {}

impl From2<u8> for Field {}

impl<T: From2<U>, U> Into2<T> for U {}

fn foo<T: Into2<Field>>() {}

fn main() {
foo::<u8>();
}
"#;
assert_no_errors!(src);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "regression_9245"
type = "bin"
authors = [""]

[dependencies]
39 changes: 39 additions & 0 deletions test_programs/compile_success_empty/regression_9245/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
pub trait Deserialize {
let N: u32;

fn deserialize(fields: [Field; N]) -> Self;
}

impl Deserialize for Field {
let N: u32 = 1;

fn deserialize(fields: [Field; Self::N]) -> Self {
fields[0]
}
}

impl<let M: u32> Deserialize for [Field; M] {
let N: u32 = <Field as Deserialize>::N * M;

fn deserialize(fields: [Field; Self::N]) -> Self {
fields
}
}

pub struct Log<let O: u32> {
pub fields: [Field; O],
}

impl<let O: u32> Deserialize for Log<O> {
let N: u32 = <[Field; O] as Deserialize>::N;

fn deserialize(fields: [Field; Self::N]) -> Self {
Self { fields: <[Field; O] as Deserialize>::deserialize(fields) }
}
}

fn main() {
let serialized = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let log = Log::<10>::deserialize(serialized);
assert_eq(serialized, log.fields);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

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

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

pub trait Deserialize {
let N: u32;

fn deserialize(_: [Field; Self::N]);
}

impl Deserialize for Field {
let N: u32 = 1;

fn deserialize(_: [Field; Self::N]) {}
}

struct Gen<T> {}

impl<T> Deserialize for Gen<T>
where
T: Deserialize,
{
let N: u32 = <T as Deserialize>::N + <T as Deserialize>::N;

fn deserialize(_: [Field; Self::N]) {}
}

fn main() {
let f = <Gen<Field> as Deserialize>::deserialize;
f([0; 2]);
}

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

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

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

pub trait From2<T> {}

impl<T> From2<T> for T {}

pub trait Into2<T> {}

impl From2<u8> for Field {}

impl<T: From2<U>, U> Into2<T> for U {}

fn foo<T: Into2<Field>>() {}

fn main() {
foo::<u8>();
}

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

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

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

Loading
Loading