From ae6c4682289eb3acc02b8e6425b20a0eeaf36873 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 10 Oct 2023 11:29:33 -0500 Subject: [PATCH 1/3] Implement automatic dereferencing for index expressions --- .../noirc_frontend/src/hir/type_check/expr.rs | 16 +++++++++++++--- .../compile_success_empty/auto_deref/Nargo.toml | 7 +++++++ .../compile_success_empty/auto_deref/src/main.nr | 5 +++++ 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 tooling/nargo_cli/tests/compile_success_empty/auto_deref/Nargo.toml create mode 100644 tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index 76a0cca4758..3b61f2b2b6b 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -128,7 +128,7 @@ impl<'interner> TypeChecker<'interner> { Type::Error }) } - HirExpression::Index(index_expr) => self.check_index_expression(index_expr), + HirExpression::Index(index_expr) => self.check_index_expression(expr_id, index_expr), HirExpression::Call(call_expr) => { self.check_if_deprecated(&call_expr.func); @@ -396,7 +396,11 @@ impl<'interner> TypeChecker<'interner> { } } - fn check_index_expression(&mut self, index_expr: expr::HirIndexExpression) -> Type { + fn check_index_expression( + &mut self, + id: &ExprId, + mut index_expr: expr::HirIndexExpression, + ) -> Type { let index_type = self.check_expression(&index_expr.index); let span = self.interner.expr_span(&index_expr.index); @@ -408,14 +412,20 @@ impl<'interner> TypeChecker<'interner> { } }); + // When writing `a[i]`, if `a : &mut ...` then automatically dereference `a` as many + // times as needed to get the underlying array. let lhs_type = self.check_expression(&index_expr.collection); + let (new_lhs, lhs_type) = self.insert_auto_dereferences(index_expr.collection, lhs_type); + index_expr.collection = new_lhs; + self.interner.replace_expr(id, HirExpression::Index(index_expr)); + match lhs_type.follow_bindings() { // XXX: We can check the array bounds here also, but it may be better to constant fold first // and have ConstId instead of ExprId for constants Type::Array(_, base_type) => *base_type, Type::Error => Type::Error, typ => { - let span = self.interner.expr_span(&index_expr.collection); + let span = self.interner.expr_span(&new_lhs); self.errors.push(TypeCheckError::TypeMismatch { expected_typ: "Array".to_owned(), expr_typ: typ.to_string(), diff --git a/tooling/nargo_cli/tests/compile_success_empty/auto_deref/Nargo.toml b/tooling/nargo_cli/tests/compile_success_empty/auto_deref/Nargo.toml new file mode 100644 index 00000000000..cc1c9a8d8f7 --- /dev/null +++ b/tooling/nargo_cli/tests/compile_success_empty/auto_deref/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "auto_deref" +type = "bin" +authors = [""] +compiler_version = "0.16.0" + +[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr new file mode 100644 index 00000000000..1225885d765 --- /dev/null +++ b/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr @@ -0,0 +1,5 @@ + +fn main() { + let a = &mut [1, 2, 3]; + assert(a[0] == 1); +} From 564b67bf542245ee3a90af6ed32f23b1e6d936b7 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 10 Oct 2023 11:45:47 -0500 Subject: [PATCH 2/3] Implement automatic dereferencing for lvalues --- .../noirc_frontend/src/hir/type_check/stmt.rs | 17 ++++++++++++++--- .../auto_deref/src/main.nr | 3 +++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/type_check/stmt.rs b/compiler/noirc_frontend/src/hir/type_check/stmt.rs index 0e843a51dc8..e289ae0fc9d 100644 --- a/compiler/noirc_frontend/src/hir/type_check/stmt.rs +++ b/compiler/noirc_frontend/src/hir/type_check/stmt.rs @@ -248,10 +248,20 @@ impl<'interner> TypeChecker<'interner> { }, ); - let (array_type, array, mutable) = self.check_lvalue(array, assign_span); - let array = Box::new(array); + let (mut lvalue_type, mut lvalue, mut mutable) = + self.check_lvalue(array, assign_span); + + // Before we check that the lvalue is an array, try to dereference it as many times + // as needed to unwrap any &mut wrappers. + while let Type::MutableReference(element) = lvalue_type.follow_bindings() { + let element_type = element.as_ref().clone(); + lvalue = HirLValue::Dereference { lvalue: Box::new(lvalue), element_type }; + lvalue_type = *element; + // We know this value to be mutable now since we found an `&mut` + mutable = true; + } - let typ = match array_type.follow_bindings() { + let typ = match lvalue_type.follow_bindings() { Type::Array(_, elem_type) => *elem_type, Type::Error => Type::Error, other => { @@ -265,6 +275,7 @@ impl<'interner> TypeChecker<'interner> { } }; + let array = Box::new(lvalue); (typ.clone(), HirLValue::Index { array, index: *index, typ }, mutable) } HirLValue::Dereference { lvalue, element_type: _ } => { diff --git a/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr index 1225885d765..ed51edde836 100644 --- a/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr +++ b/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr @@ -2,4 +2,7 @@ fn main() { let a = &mut [1, 2, 3]; assert(a[0] == 1); + + a[0] = 4; + assert(a[0] == 4); } From 8b8f1f9203ba2c299cc7886d5a3b8a0261a882e9 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Tue, 10 Oct 2023 11:56:57 -0500 Subject: [PATCH 3/3] Add more &mut --- .../tests/compile_success_empty/auto_deref/src/main.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr b/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr index ed51edde836..e0b4a447fd0 100644 --- a/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr +++ b/tooling/nargo_cli/tests/compile_success_empty/auto_deref/src/main.nr @@ -1,6 +1,6 @@ fn main() { - let a = &mut [1, 2, 3]; + let a = &mut &mut &mut [1, 2, 3]; assert(a[0] == 1); a[0] = 4;