Skip to content

Commit

Permalink
fix: Apply self type from generic trait constraint before instantiati…
Browse files Browse the repository at this point in the history
…ng identifiers (#5087)

# Description

## Problem\*

Resolves #5063 

## Summary\*

After the turbofish PRs we want the ability to instantiate a variable
from a generic trait. This was possible but it required a redundant type
annotiation like such (assume `H` has been specified with a `where`
clause):
```rust
let hasher: H = H::default()
```
Similarly to trait generics, we now add type bindings from a trait
constraint if the trait impl is assumed to exist.
We now can just do:
```rust
let hasher = H::default()
```

## 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.
  • Loading branch information
vezenovm committed May 23, 2024
1 parent 23a6477 commit 2b4755c
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 7 deletions.
12 changes: 11 additions & 1 deletion compiler/noirc_frontend/src/hir/type_check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ impl<'interner> TypeChecker<'interner> {
// We need to do this first since otherwise instantiating the type below
// will replace each trait generic with a fresh type variable, rather than
// the type used in the trait constraint (if it exists). See #4088.
if let ImplKind::TraitMethod(_, constraint, _) = &ident.impl_kind {
if let ImplKind::TraitMethod(_, constraint, assumed) = &ident.impl_kind {
let the_trait = self.interner.get_trait(constraint.trait_id);
assert_eq!(the_trait.generics.len(), constraint.trait_generics.len());

Expand All @@ -381,6 +381,16 @@ impl<'interner> TypeChecker<'interner> {
bindings.insert(param.id(), (param.clone(), arg.clone()));
}
}

// If the trait impl is already assumed to exist we should add any type bindings for `Self`.
// Otherwise `self` will be replaced with a fresh type variable, which will require the user
// to specify a redundant type annotation.
if *assumed {
bindings.insert(
the_trait.self_type_typevar_id,
(the_trait.self_type_typevar.clone(), constraint.typ.clone()),
);
}
}

// An identifiers type may be forall-quantified in the case of generic functions.
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1430,14 +1430,14 @@ fn specify_method_types_with_turbofish() {
}
impl<T> Foo<T> {
fn generic_method<U>(_self: Self) where U: Default {
fn generic_method<U>(_self: Self) -> U where U: Default {
U::default()
}
}
fn main() {
let foo: Foo<Field> = Foo { inner: 1 };
foo.generic_method::<Field>();
let _ = foo.generic_method::<Field>();
}
"#;
let errors = get_program_errors(src);
Expand Down
2 changes: 1 addition & 1 deletion noir_stdlib/src/eddsa.nr
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ where H: Hasher + Default {
// Ensure S < Subgroup Order
assert(signature_s.lt(bjj.suborder));
// Calculate the h = H(R, A, msg)
let mut hasher: H = H::default();
let mut hasher = H::default();
hasher.write(signature_r8_x);
hasher.write(signature_r8_y);
hasher.write(pub_key_x);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ fn main(x: Field, y: pub Field) {

fn hash_simple_array<H>(input: [Field; 2]) -> Field where H: Hasher + Default {
// Check that we can call a trait method instead of a trait implementation
// TODO(https://github.com/noir-lang/noir/issues/5063): Need to remove the need for this type annotation
// Curently, without the annotation we will get `Expression type is ambiguous` when trying to use the `hasher`
let mut hasher: H = H::default();
let mut hasher = H::default();
// Regression that the object is converted to a mutable reference type `&mut _`.
// Otherwise will see `Expected type &mut _, found type H`.
// Then we need to make sure to also auto dereference later in the type checking process
Expand Down

0 comments on commit 2b4755c

Please sign in to comment.