Skip to content

Commit 2b4755c

Browse files
authored
fix: Apply self type from generic trait constraint before instantiating 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.
1 parent 23a6477 commit 2b4755c

4 files changed

Lines changed: 15 additions & 7 deletions

File tree

  • compiler/noirc_frontend/src
  • noir_stdlib/src
  • test_programs/execution_success/turbofish_call_func_diff_types/src

compiler/noirc_frontend/src/hir/type_check/expr.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl<'interner> TypeChecker<'interner> {
371371
// We need to do this first since otherwise instantiating the type below
372372
// will replace each trait generic with a fresh type variable, rather than
373373
// the type used in the trait constraint (if it exists). See #4088.
374-
if let ImplKind::TraitMethod(_, constraint, _) = &ident.impl_kind {
374+
if let ImplKind::TraitMethod(_, constraint, assumed) = &ident.impl_kind {
375375
let the_trait = self.interner.get_trait(constraint.trait_id);
376376
assert_eq!(the_trait.generics.len(), constraint.trait_generics.len());
377377

@@ -381,6 +381,16 @@ impl<'interner> TypeChecker<'interner> {
381381
bindings.insert(param.id(), (param.clone(), arg.clone()));
382382
}
383383
}
384+
385+
// If the trait impl is already assumed to exist we should add any type bindings for `Self`.
386+
// Otherwise `self` will be replaced with a fresh type variable, which will require the user
387+
// to specify a redundant type annotation.
388+
if *assumed {
389+
bindings.insert(
390+
the_trait.self_type_typevar_id,
391+
(the_trait.self_type_typevar.clone(), constraint.typ.clone()),
392+
);
393+
}
384394
}
385395

386396
// An identifiers type may be forall-quantified in the case of generic functions.

compiler/noirc_frontend/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,14 +1430,14 @@ fn specify_method_types_with_turbofish() {
14301430
}
14311431
14321432
impl<T> Foo<T> {
1433-
fn generic_method<U>(_self: Self) where U: Default {
1433+
fn generic_method<U>(_self: Self) -> U where U: Default {
14341434
U::default()
14351435
}
14361436
}
14371437
14381438
fn main() {
14391439
let foo: Foo<Field> = Foo { inner: 1 };
1440-
foo.generic_method::<Field>();
1440+
let _ = foo.generic_method::<Field>();
14411441
}
14421442
"#;
14431443
let errors = get_program_errors(src);

noir_stdlib/src/eddsa.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ where H: Hasher + Default {
4545
// Ensure S < Subgroup Order
4646
assert(signature_s.lt(bjj.suborder));
4747
// Calculate the h = H(R, A, msg)
48-
let mut hasher: H = H::default();
48+
let mut hasher = H::default();
4949
hasher.write(signature_r8_x);
5050
hasher.write(signature_r8_y);
5151
hasher.write(pub_key_x);

test_programs/execution_success/turbofish_call_func_diff_types/src/main.nr

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ fn main(x: Field, y: pub Field) {
2323

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

0 commit comments

Comments
 (0)