diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 87ff45f8f1a..d96d4a35e1f 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -1437,6 +1437,8 @@ impl NodeInterner { let mut matching_impls = Vec::new(); + let mut where_clause_errors = Vec::new(); + for (existing_object_type2, impl_kind) in impls { // Bug: We're instantiating only the object type's generics here, not all of the trait's generics like we need to let (existing_object_type, instantiation_bindings) = @@ -1471,14 +1473,17 @@ impl NodeInterner { let trait_impl = self.get_trait_implementation(*impl_id); let trait_impl = trait_impl.borrow(); - if let Err(mut errors) = self.validate_where_clause( + if let Err(errors) = self.validate_where_clause( &trait_impl.where_clause, &mut fresh_bindings, &instantiation_bindings, recursion_limit, ) { - errors.push(make_constraint()); - return Err(errors); + // Only keep the first errors we get from a failing where clause + if where_clause_errors.is_empty() { + where_clause_errors.extend(errors); + } + continue; } } @@ -1491,7 +1496,8 @@ impl NodeInterner { *type_bindings = fresh_bindings; Ok(impl_) } else if matching_impls.is_empty() { - Err(vec![make_constraint()]) + where_clause_errors.push(make_constraint()); + Err(where_clause_errors) } else { // multiple matching impls, type annotations needed Err(vec![]) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 8ce430b6e48..df85cf0dda4 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -2846,3 +2846,75 @@ fn error_on_cast_over_type_variable() { CompilationError::TypeError(TypeCheckError::TypeMismatch { .. }) )); } + +#[test] +fn trait_impl_for_a_type_that_implements_another_trait() { + let src = r#" + trait One { + fn one(self) -> i32; + } + + impl One for i32 { + fn one(self) -> i32 { + self + } + } + + trait Two { + fn two(self) -> i32; + } + + impl Two for T where T: One { + fn two(self) -> i32 { + self.one() + 1 + } + } + + fn use_it(t: T) -> i32 where T: Two { + Two::two(t) + } + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn trait_impl_for_a_type_that_implements_another_trait_with_another_impl_used() { + let src = r#" + trait One { + fn one(self) -> i32; + } + + impl One for i32 { + fn one(self) -> i32 { + let _ = self; + 1 + } + } + + trait Two { + fn two(self) -> i32; + } + + impl Two for T where T: One { + fn two(self) -> i32 { + self.one() + 1 + } + } + + impl Two for u32 { + fn two(self) -> i32 { + let _ = self; + 0 + } + } + + fn use_it(t: u32) -> i32 { + Two::two(t) + } + + fn main() {} + "#; + assert_no_errors(src); +}