Skip to content

Commit

Permalink
fix: method resolution when calling an &mut method with an &mut o…
Browse files Browse the repository at this point in the history
…bject type (#1947)

Fix method resolution bug

Co-authored-by: TomAFrench <tom@tomfren.ch>
  • Loading branch information
jfecher and TomAFrench authored Jul 17, 2023
1 parent ed9bf9e commit 73c2e94
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ fn main(mut x: Field) {
s.add2();
assert(s.y == 5);

// Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T
let s_ref = &mut s;
s_ref.add2();
assert(s.y == 7);

// Test that normal mutable variables are still copied
let mut a = 0;
mutate_copy(a);
Expand Down
18 changes: 11 additions & 7 deletions crates/noirc_frontend/src/hir/type_check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<'interner> TypeChecker<'interner> {
HirExpression::MethodCall(mut method_call) => {
let object_type = self.check_expression(&method_call.object).follow_bindings();
let method_name = method_call.method.0.contents.as_str();
match self.lookup_method(object_type.clone(), method_name, expr_id) {
match self.lookup_method(&object_type, method_name, expr_id) {
Some(method_id) => {
let mut args =
vec![(object_type, self.interner.expr_span(&method_call.object))];
Expand Down Expand Up @@ -287,11 +287,12 @@ impl<'interner> TypeChecker<'interner> {
if matches!(expected_object_type.follow_bindings(), Type::MutableReference(_)) {
let actual_type = argument_types[0].0.follow_bindings();

if let Err(error) = verify_mutable_reference(self.interner, method_call.object) {
self.errors.push(TypeCheckError::ResolverError(error));
}

if !matches!(actual_type, Type::MutableReference(_)) {
if let Err(error) = verify_mutable_reference(self.interner, method_call.object)
{
self.errors.push(TypeCheckError::ResolverError(error));
}

let new_type = Type::MutableReference(Box::new(actual_type));

argument_types[0].0 = new_type.clone();
Expand Down Expand Up @@ -719,11 +720,11 @@ impl<'interner> TypeChecker<'interner> {

fn lookup_method(
&mut self,
object_type: Type,
object_type: &Type,
method_name: &str,
expr_id: &ExprId,
) -> Option<FuncId> {
match &object_type {
match object_type {
Type::Struct(typ, _args) => {
match self.interner.lookup_method(typ.borrow().id, method_name) {
Some(method_id) => Some(method_id),
Expand All @@ -738,6 +739,9 @@ impl<'interner> TypeChecker<'interner> {
}
}
}
// Mutable references to another type should resolve to methods of their element type.
// This may be a struct or a primitive type.
Type::MutableReference(element) => self.lookup_method(element, method_name, expr_id),
// If we fail to resolve the object to a struct type, we have no way of type
// checking its arguments as we can't even resolve the name of the function
Type::Error => None,
Expand Down

0 comments on commit 73c2e94

Please sign in to comment.