Skip to content

Commit

Permalink
fix: ensure where clauses propagated to trait default definitions (#4894
Browse files Browse the repository at this point in the history
)

# Description

## Problem\*

Resolves #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<T> Foo for Bar<T> 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 <jake@aztecprotocol.com>
  • Loading branch information
michaeljklein and jfecher committed Apr 29, 2024
1 parent 9d53496 commit aaac0f6
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 5 deletions.
11 changes: 6 additions & 5 deletions compiler/noirc_frontend/src/hir/resolution/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
Expand Down Expand Up @@ -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(),
Expand Down
21 changes: 21 additions & 0 deletions compiler/noirc_frontend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> 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 = "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "impl_from_where_impl"
type = "bin"
authors = [""]
compiler_version = ">=0.27.0"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
trait Bar {
fn ok(self) -> Self;

fn ref_ok(self) -> Self {
self.ok()
}
}

impl<T> Bar for (T, T) where T: Bar {
fn ok(self) -> Self {
self
}
}

fn main() {}

0 comments on commit aaac0f6

Please sign in to comment.