From aaac0f6bffbe11eb090145354f1b82919bb93cb7 Mon Sep 17 00:00:00 2001 From: Michael J Klein Date: Mon, 29 Apr 2024 15:22:19 -0400 Subject: [PATCH] fix: ensure where clauses propagated to trait default definitions (#4894) # Description ## Problem\* Resolves https://github.com/noir-lang/noir/issues/4847 ## Summary\* Before this PR, we were simply copying the default definition as an unresolved `impl` method, without adding in any `where` clauses from the top level of the `impl`. This PR propagates the `where` clauses into default definitions when they're used. For example: ```rust impl Foo for Bar where T: Foo { fn qux(self) -> bool { ^ we want an implicit "where T: Foo" here .. } } ``` ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: jfecher --- .../src/hir/resolution/traits.rs | 11 +++++----- compiler/noirc_frontend/src/tests.rs | 21 +++++++++++++++++++ .../impl_from_where_impl/Nargo.toml | 7 +++++++ .../impl_from_where_impl/src/main.nr | 15 +++++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml create mode 100644 test_programs/compile_success_empty/impl_from_where_impl/src/main.nr diff --git a/compiler/noirc_frontend/src/hir/resolution/traits.rs b/compiler/noirc_frontend/src/hir/resolution/traits.rs index ccae8c6dd0..3d355fd444 100644 --- a/compiler/noirc_frontend/src/hir/resolution/traits.rs +++ b/compiler/noirc_frontend/src/hir/resolution/traits.rs @@ -124,6 +124,7 @@ fn resolve_trait_methods( let mut resolver = Resolver::new(interner, &path_resolver, def_maps, file); resolver.add_generics(generics); + resolver.add_existing_generics(&unresolved_trait.trait_def.generics, trait_generics); resolver.add_existing_generic("Self", name_span, self_typevar); resolver.set_self_type(Some(self_type.clone())); @@ -207,16 +208,16 @@ fn collect_trait_impl_methods( if overrides.is_empty() { if let Some(default_impl) = &method.default_impl { + // copy 'where' clause from unresolved trait impl + let mut default_impl_clone = default_impl.clone(); + default_impl_clone.def.where_clause.extend(trait_impl.where_clause.clone()); + let func_id = interner.push_empty_fn(); let module = ModuleId { local_id: trait_impl.module_id, krate: crate_id }; let location = Location::new(default_impl.def.span, trait_impl.file_id); interner.push_function(func_id, &default_impl.def, module, location); func_ids_in_trait.insert(func_id); - ordered_methods.push(( - method.default_impl_module_id, - func_id, - *default_impl.clone(), - )); + ordered_methods.push((method.default_impl_module_id, func_id, *default_impl_clone)); } else { let error = DefCollectorErrorKind::TraitMissingMethod { trait_name: interner.get_trait(trait_id).name.clone(), diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index cf2d7dbe15..b2cc7eee9f 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -746,6 +746,27 @@ mod test { } } + #[test] + fn test_impl_self_within_default_def() { + let src = " + trait Bar { + fn ok(self) -> Self; + + fn ref_ok(self) -> Self { + self.ok() + } + } + + impl Bar for (T, T) where T: Bar { + fn ok(self) -> Self { + self + } + }"; + let errors = get_program_errors(src); + errors.iter().for_each(|err| println!("{:?}", err)); + assert!(errors.is_empty()); + } + #[test] fn check_trait_as_type_as_fn_parameter() { let src = " diff --git a/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml b/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml new file mode 100644 index 0000000000..5894e457dd --- /dev/null +++ b/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "impl_from_where_impl" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] diff --git a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr new file mode 100644 index 0000000000..3cec46bdfc --- /dev/null +++ b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr @@ -0,0 +1,15 @@ +trait Bar { + fn ok(self) -> Self; + + fn ref_ok(self) -> Self { + self.ok() + } +} + +impl Bar for (T, T) where T: Bar { + fn ok(self) -> Self { + self + } +} + +fn main() {}