Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Apply self type from generic trait constraint before instantiating identifiers #5087

Merged
merged 4 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
jfecher marked this conversation as resolved.
Show resolved Hide resolved
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
3 changes: 2 additions & 1 deletion tooling/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ pub(crate) fn run(args: InfoCommand, config: NargoConfig) -> Result<(), CliError
} else {
// Otherwise print human-readable table.
if !info_report.programs.is_empty() {
let mut program_table = table!([Fm->"Package", Fm->"Function", Fm->"Expression Width", Fm->"ACIR Opcodes"]);
let mut program_table =
table!([Fm->"Package", Fm->"Function", Fm->"Expression Width", Fm->"ACIR Opcodes"]);

for program_info in info_report.programs {
let program_rows: Vec<Row> = program_info.into();
Expand Down
Loading