From ae42a7a2baab0121c54c1c380c6176d26035b9cf Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 21 Aug 2025 11:26:12 -0300 Subject: [PATCH] fix(expand): correctly handle nested dereferences --- .../nested_dereferences/Nargo.toml | 6 +++++ .../nested_dereferences/src/main.nr | 19 ++++++++++++++ .../execute__tests__expanded.snap | 20 ++++++++++++++ ..._tests__force_brillig_false_inliner_0.snap | 26 +++++++++++++++++++ tooling/nargo_expand/src/printer/hir.rs | 25 ++++++++++++++++-- 5 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 test_programs/compile_success_empty/nested_dereferences/Nargo.toml create mode 100644 test_programs/compile_success_empty/nested_dereferences/src/main.nr create mode 100644 tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_dereferences/execute__tests__expanded.snap create mode 100644 tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_dereferences/execute__tests__force_brillig_false_inliner_0.snap diff --git a/test_programs/compile_success_empty/nested_dereferences/Nargo.toml b/test_programs/compile_success_empty/nested_dereferences/Nargo.toml new file mode 100644 index 00000000000..f381a2a9e6e --- /dev/null +++ b/test_programs/compile_success_empty/nested_dereferences/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "nested_dereferences" +type = "bin" +authors = [""] + +[dependencies] diff --git a/test_programs/compile_success_empty/nested_dereferences/src/main.nr b/test_programs/compile_success_empty/nested_dereferences/src/main.nr new file mode 100644 index 00000000000..a8bbd42ecb2 --- /dev/null +++ b/test_programs/compile_success_empty/nested_dereferences/src/main.nr @@ -0,0 +1,19 @@ +struct Foo { + inner: Field, +} + +fn main() { + let mut var = Foo { inner: 0 }; + let ref = &mut &mut var; + + let mut array = [ref, ref]; + assert((**array[0]).inner == 0); + + (*(*array[0])).inner = 1; + (**array[1]).inner = 2; + + assert(var.inner == 2); + assert((**ref).inner == 2); + assert((**array[0]).inner == 2); + assert((**array[1]).inner == 2); +} diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_dereferences/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_dereferences/execute__tests__expanded.snap new file mode 100644 index 00000000000..939a3913244 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_dereferences/execute__tests__expanded.snap @@ -0,0 +1,20 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +struct Foo { + inner: Field, +} + +fn main() { + let mut var: Foo = Foo { inner: 0_Field }; + let ref: &mut &mut Foo = &mut &mut var; + let mut array: [&mut &mut Foo; 2] = [ref, ref]; + assert((**array[0_u32]).inner == 0_Field); + (*(*(array[0_u32]))).inner = 1_Field; + (*(*(array[1_u32]))).inner = 2_Field; + assert(var.inner == 2_Field); + assert((**ref).inner == 2_Field); + assert((**array[0_u32]).inner == 2_Field); + assert((**array[1_u32]).inner == 2_Field); +} diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_dereferences/execute__tests__force_brillig_false_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_dereferences/execute__tests__force_brillig_false_inliner_0.snap new file mode 100644 index 00000000000..7de940827c8 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_dereferences/execute__tests__force_brillig_false_inliner_0.snap @@ -0,0 +1,26 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: artifact +--- +{ + "noir_version": "[noir_version]", + "hash": "[hash]", + "abi": { + "parameters": [], + "return_type": null, + "error_types": {} + }, + "bytecode": [ + "func 0", + "current witness index : _0", + "private parameters indices : []", + "public parameters indices : []", + "return value indices : []" + ], + "debug_symbols": "XY5BCsQwCEXv4rqLWfcqw1BsaosgJtikMITefWyYQOlK/3/6tcJCc9km1jXuML4rzMYivE0SA2aO6m49B+hyykbkFty4byU00gyjFpEBDpTShvaE2mpGc/oagHTx6oErC13d+XGBge158UBjnIX+ci0abjR/Uyf942Qx0FKMrqTGPPsH", + "file_map": {}, + "names": [ + "main" + ], + "brillig_names": [] +} diff --git a/tooling/nargo_expand/src/printer/hir.rs b/tooling/nargo_expand/src/printer/hir.rs index ff5595089c9..37e6d422c12 100644 --- a/tooling/nargo_expand/src/printer/hir.rs +++ b/tooling/nargo_expand/src/printer/hir.rs @@ -5,7 +5,7 @@ use noirc_frontend::{ hir_def::{ expr::{ Constructor, HirArrayLiteral, HirBlockExpression, HirCallExpression, HirExpression, - HirIdent, HirLambda, HirLiteral, HirMatch, ImplKind, TraitItem, + HirIdent, HirLambda, HirLiteral, HirMatch, HirPrefixExpression, ImplKind, TraitItem, }, stmt::{HirLValue, HirPattern, HirStatement}, }, @@ -170,7 +170,20 @@ impl ItemPrinter<'_, '_> { } } HirExpression::MemberAccess(hir_member_access) => { - self.show_hir_expression_id_maybe_inside_parens(hir_member_access.lhs); + let lhs_exp = self.interner.expression(&hir_member_access.lhs); + + if let HirExpression::Prefix(HirPrefixExpression { + operator: UnaryOp::Dereference { implicitly_added: false }, + .. + }) = lhs_exp + { + // In general we don't need parentheses around dereferences, but here we do + self.push('('); + self.show_hir_expression(lhs_exp, hir_member_access.lhs); + self.push(')'); + } else { + self.show_hir_expression_id_maybe_inside_parens(hir_member_access.lhs); + } self.push('.'); self.push_str(&hir_member_access.rhs.to_string()); } @@ -666,7 +679,15 @@ impl ItemPrinter<'_, '_> { self.show_hir_ident(hir_ident, None); } HirLValue::MemberAccess { object, field_name, field_index: _, typ: _, location: _ } => { + let object_is_dereference = + matches!(*object, HirLValue::Dereference { implicitly_added: false, .. }); + if object_is_dereference { + self.push('('); + } self.show_hir_lvalue(*object); + if object_is_dereference { + self.push(')'); + } self.push('.'); self.push_str(&field_name.to_string()); }