diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 87f304c4aef..89af482a168 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -827,6 +827,7 @@ impl Elaborator<'_> { fn check_method_call_visibility(&mut self, func_id: FuncId, object_type: &Type, name: &Ident) { if !method_call_is_visible( + self.self_type.as_ref(), object_type, func_id, self.module_id(), diff --git a/compiler/noirc_frontend/src/hir/resolution/visibility.rs b/compiler/noirc_frontend/src/hir/resolution/visibility.rs index 0c88414021c..f3907fc9833 100644 --- a/compiler/noirc_frontend/src/hir/resolution/visibility.rs +++ b/compiler/noirc_frontend/src/hir/resolution/visibility.rs @@ -124,6 +124,7 @@ fn type_member_is_visible( } pub fn method_call_is_visible( + self_type: Option<&Type>, object_type: &Type, func_id: FuncId, current_module: ModuleId, @@ -155,6 +156,14 @@ pub fn method_call_is_visible( ); } + // A private method defined on `Foo` should be visible when calling + // it from an impl on `Foo`, even though the generics are different. + if self_type + .is_some_and(|self_type| is_same_type_regardless_generics(self_type, object_type)) + { + return true; + } + if let Some(struct_id) = func_meta.type_id { return struct_member_is_visible( struct_id, @@ -178,3 +187,24 @@ pub fn method_call_is_visible( } } } + +fn is_same_type_regardless_generics(type1: &Type, type2: &Type) -> bool { + if type1 == type2 { + return true; + } + + match (type1.follow_bindings(), type2.follow_bindings()) { + (Type::Array(..), Type::Array(..)) => true, + (Type::Slice(..), Type::Slice(..)) => true, + (Type::String(..), Type::String(..)) => true, + (Type::FmtString(..), Type::FmtString(..)) => true, + (Type::Tuple(..), Type::Tuple(..)) => true, + (Type::Function(..), Type::Function(..)) => true, + (Type::DataType(data_type1, ..), Type::DataType(data_type2, ..)) => { + data_type1.borrow().id == data_type2.borrow().id + } + (Type::Reference(type1, _), _) => is_same_type_regardless_generics(&type1, type2), + (_, Type::Reference(type2, _)) => is_same_type_regardless_generics(type1, &type2), + _ => false, + } +} diff --git a/compiler/noirc_frontend/src/tests/visibility.rs b/compiler/noirc_frontend/src/tests/visibility.rs index 26bf54a7d7c..6673d16e5c9 100644 --- a/compiler/noirc_frontend/src/tests/visibility.rs +++ b/compiler/noirc_frontend/src/tests/visibility.rs @@ -586,3 +586,53 @@ fn errors_on_use_of_private_exported_item() { "#; check_errors!(src); } + +#[named] +#[test] +fn private_impl_method_on_another_module_1() { + let src = r#" + pub mod bar { + pub struct Foo {} + } + + impl bar::Foo { + fn foo(self) { + let _ = self; + } + + fn bar(self) { + self.foo(); + } + } + + fn main() {} + "#; + assert_no_errors!(src); +} + +#[named] +#[test] +fn private_impl_method_on_another_module_2() { + let src = r#" + pub mod bar { + pub struct Foo {} + } + + impl bar::Foo { + fn foo(self) { + let _ = self; + } + } + + impl bar::Foo { + fn bar(self) { + let _ = self; + let foo = bar::Foo:: {}; + foo.foo(); + } + } + + fn main() {} + "#; + assert_no_errors!(src); +} diff --git a/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/Nargo.toml b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/Nargo.toml new file mode 100644 index 00000000000..b8d13d0bb1c --- /dev/null +++ b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/Nargo.toml @@ -0,0 +1,7 @@ + + [package] + name = "noirc_frontend_tests_visibility_private_impl_method_on_another_module_1" + type = "bin" + authors = [""] + + [dependencies] \ No newline at end of file diff --git a/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/src/main.nr b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/src/main.nr new file mode 100644 index 00000000000..cf3f60915a0 --- /dev/null +++ b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/src/main.nr @@ -0,0 +1,17 @@ + + pub mod bar { + pub struct Foo {} + } + + impl bar::Foo { + fn foo(self) { + let _ = self; + } + + fn bar(self) { + self.foo(); + } + } + + fn main() {} + \ No newline at end of file diff --git a/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/src_hash.txt b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/src_hash.txt new file mode 100644 index 00000000000..a718d7a1ba9 --- /dev/null +++ b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/src_hash.txt @@ -0,0 +1 @@ +18298111048694488524 \ No newline at end of file diff --git a/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/Nargo.toml b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/Nargo.toml new file mode 100644 index 00000000000..2287d72570d --- /dev/null +++ b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/Nargo.toml @@ -0,0 +1,7 @@ + + [package] + name = "noirc_frontend_tests_visibility_private_impl_method_on_another_module_2" + type = "bin" + authors = [""] + + [dependencies] \ No newline at end of file diff --git a/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/src/main.nr b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/src/main.nr new file mode 100644 index 00000000000..269c57b895a --- /dev/null +++ b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/src/main.nr @@ -0,0 +1,21 @@ + + pub mod bar { + pub struct Foo {} + } + + impl bar::Foo { + fn foo(self) { + let _ = self; + } + } + + impl bar::Foo { + fn bar(self) { + let _ = self; + let foo = bar::Foo:: {}; + foo.foo(); + } + } + + fn main() {} + \ No newline at end of file diff --git a/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/src_hash.txt b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/src_hash.txt new file mode 100644 index 00000000000..bb99826db06 --- /dev/null +++ b/test_programs/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/src_hash.txt @@ -0,0 +1 @@ +13369966237074401506 \ No newline at end of file diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index 75cbfb427b8..0db1e11a88a 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -732,6 +732,7 @@ impl<'a> NodeFinder<'a> { if is_primitive && !method_call_is_visible( + self.self_type.as_ref(), typ, func_id, self.module_id, diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module/execute__tests__expanded.snap new file mode 100644 index 00000000000..bf738a6e67b --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module/execute__tests__expanded.snap @@ -0,0 +1,19 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +pub mod bar { + pub struct Foo {} + + impl Foo { + fn foo(self) { + let _: Self = self; + } + + fn bar(self) { + self.foo(); + } + } +} + +fn main() {} diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/execute__tests__expanded.snap new file mode 100644 index 00000000000..bf738a6e67b --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_1/execute__tests__expanded.snap @@ -0,0 +1,19 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +pub mod bar { + pub struct Foo {} + + impl Foo { + fn foo(self) { + let _: Self = self; + } + + fn bar(self) { + self.foo(); + } + } +} + +fn main() {} diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/execute__tests__expanded.snap new file mode 100644 index 00000000000..60623161d5e --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/noirc_frontend_tests_visibility_private_impl_method_on_another_module_2/execute__tests__expanded.snap @@ -0,0 +1,23 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +pub mod bar { + pub struct Foo {} + + impl Foo { + fn foo(self) { + let _: Self = self; + } + } + + impl Foo { + fn bar(self) { + let _: Self = self; + let foo: Foo = Foo:: {}; + foo.foo(); + } + } +} + +fn main() {}