Skip to content

Commit

Permalink
Merge branch 'master' into 6186-bench-acvm
Browse files Browse the repository at this point in the history
  • Loading branch information
aakoshh authored Oct 9, 2024
2 parents c41f9d7 + 70cbeb4 commit 7cc0a4c
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 69 deletions.
20 changes: 19 additions & 1 deletion compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use crate::{
},
hir::{
comptime::{self, InterpreterError},
resolution::errors::ResolverError,
resolution::{
errors::ResolverError, import::PathResolutionError, visibility::method_call_is_visible,
},
type_check::{generics::TraitGenerics, TypeCheckError},
},
hir_def::{
Expand Down Expand Up @@ -449,6 +451,8 @@ impl<'context> Elaborator<'context> {
let method_call =
HirMethodCallExpression { method, object, arguments, location, generics };

self.check_method_call_visibility(func_id, &object_type, &method_call.method);

// Desugar the method call into a normal, resolved function call
// so that the backend doesn't need to worry about methods
// TODO: update object_type here?
Expand Down Expand Up @@ -487,6 +491,20 @@ impl<'context> Elaborator<'context> {
}
}

fn check_method_call_visibility(&mut self, func_id: FuncId, object_type: &Type, name: &Ident) {
if !method_call_is_visible(
object_type,
func_id,
self.module_id(),
self.interner,
self.def_maps,
) {
self.push_err(ResolverError::PathResolutionError(PathResolutionError::Private(
name.clone(),
)));
}
}

fn elaborate_constructor(
&mut self,
constructor: ConstructorExpression,
Expand Down
5 changes: 3 additions & 2 deletions compiler/noirc_frontend/src/elaborator/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use crate::{
},
hir::{
resolution::{
errors::ResolverError, import::PathResolutionError, visibility::struct_field_is_visible,
errors::ResolverError, import::PathResolutionError,
visibility::struct_member_is_visible,
},
type_check::{Source, TypeCheckError},
},
Expand Down Expand Up @@ -508,7 +509,7 @@ impl<'context> Elaborator<'context> {
visibility: ItemVisibility,
span: Span,
) {
if !struct_field_is_visible(struct_type, visibility, self.module_id(), self.def_maps) {
if !struct_member_is_visible(struct_type.id, visibility, self.module_id(), self.def_maps) {
self.push_err(ResolverError::PathResolutionError(PathResolutionError::Private(
Ident::new(field_name.to_string(), span),
)));
Expand Down
57 changes: 51 additions & 6 deletions compiler/noirc_frontend/src/hir/resolution/visibility.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::graph::CrateId;
use crate::StructType;
use crate::node_interner::{FuncId, NodeInterner, StructId};
use crate::Type;

use std::collections::BTreeMap;

use crate::ast::ItemVisibility;
use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId};
use crate::hir::def_map::{CrateDefMap, DefMaps, LocalModuleId, ModuleId};

// Returns false if the given private function is being called from a non-child module, or
// if the given pub(crate) function is being called from another crate. Otherwise returns true.
Expand Down Expand Up @@ -64,19 +65,19 @@ fn module_is_parent_of_struct_module(
module_data.is_struct && module_data.parent == Some(current)
}

pub fn struct_field_is_visible(
struct_type: &StructType,
pub fn struct_member_is_visible(
struct_id: StructId,
visibility: ItemVisibility,
current_module_id: ModuleId,
def_maps: &BTreeMap<CrateId, CrateDefMap>,
) -> bool {
match visibility {
ItemVisibility::Public => true,
ItemVisibility::PublicCrate => {
struct_type.id.parent_module_id(def_maps).krate == current_module_id.krate
struct_id.parent_module_id(def_maps).krate == current_module_id.krate
}
ItemVisibility::Private => {
let struct_parent_module_id = struct_type.id.parent_module_id(def_maps);
let struct_parent_module_id = struct_id.parent_module_id(def_maps);
if struct_parent_module_id.krate != current_module_id.krate {
return false;
}
Expand All @@ -94,3 +95,47 @@ pub fn struct_field_is_visible(
}
}
}

pub fn method_call_is_visible(
object_type: &Type,
func_id: FuncId,
current_module: ModuleId,
interner: &NodeInterner,
def_maps: &DefMaps,
) -> bool {
let modifiers = interner.function_modifiers(&func_id);
match modifiers.visibility {
ItemVisibility::Public => true,
ItemVisibility::PublicCrate => {
if object_type.is_primitive() {
current_module.krate.is_stdlib()
} else {
interner.function_module(func_id).krate == current_module.krate
}
}
ItemVisibility::Private => {
if object_type.is_primitive() {
let func_module = interner.function_module(func_id);
can_reference_module_id(
def_maps,
current_module.krate,
current_module.local_id,
func_module,
modifiers.visibility,
)
} else {
let func_meta = interner.function_meta(&func_id);
if let Some(struct_id) = func_meta.struct_id {
struct_member_is_visible(
struct_id,
modifiers.visibility,
current_module,
def_maps,
)
} else {
true
}
}
}
}
}
28 changes: 28 additions & 0 deletions compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,34 @@ impl Type {
}
}

pub fn is_primitive(&self) -> bool {
match self.follow_bindings() {
Type::FieldElement
| Type::Array(_, _)
| Type::Slice(_)
| Type::Integer(..)
| Type::Bool
| Type::String(_)
| Type::FmtString(_, _)
| Type::Unit
| Type::Function(..)
| Type::Tuple(..) => true,
Type::Alias(alias_type, generics) => {
alias_type.borrow().get_type(&generics).is_primitive()
}
Type::MutableReference(typ) => typ.is_primitive(),
Type::Struct(..)
| Type::TypeVariable(..)
| Type::TraitAsType(..)
| Type::NamedGeneric(..)
| Type::Forall(..)
| Type::Constant(..)
| Type::Quoted(..)
| Type::InfixExpr(..)
| Type::Error => false,
}
}

pub fn find_numeric_type_vars(&self, found_names: &mut Vec<String>) {
// Return whether the named generic has a Kind::Numeric and save its name
let named_generic_is_numeric = |typ: &Type, found_names: &mut Vec<String>| {
Expand Down
55 changes: 55 additions & 0 deletions compiler/noirc_frontend/src/tests/visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,61 @@ fn errors_if_trying_to_access_public_function_inside_private_module() {
assert_eq!(ident.to_string(), "bar");
}

#[test]
fn warns_if_calling_private_struct_method() {
let src = r#"
mod moo {
pub struct Foo {}
impl Foo {
fn bar(self) {
let _ = self;
}
}
}
pub fn method(foo: moo::Foo) {
foo.bar()
}
fn main() {}
"#;

let errors = get_program_errors(src);
assert_eq!(errors.len(), 1);

let CompilationError::ResolverError(ResolverError::PathResolutionError(
PathResolutionError::Private(ident),
)) = &errors[0].0
else {
panic!("Expected a private error");
};

assert_eq!(ident.to_string(), "bar");
}

#[test]
fn does_not_warn_if_calling_pub_crate_struct_method_from_same_crate() {
let src = r#"
mod moo {
pub struct Foo {}
impl Foo {
pub(crate) fn bar(self) {
let _ = self;
}
}
}
pub fn method(foo: moo::Foo) {
foo.bar()
}
fn main() {}
"#;
assert_no_errors(src);
}

#[test]
fn does_not_error_if_calling_private_struct_function_from_same_struct() {
let src = r#"
Expand Down
Loading

0 comments on commit 7cc0a4c

Please sign in to comment.