Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: turn TypeIsMorePrivateThenItem into an error #6953

Merged
merged 4 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions compiler/noirc_frontend/src/elaborator/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ impl<'context> Elaborator<'context> {
parameters,
return_type,
where_clause,
unresolved_trait.trait_def.visibility,
func_id,
);

Expand Down Expand Up @@ -189,6 +190,7 @@ impl<'context> Elaborator<'context> {
parameters: &[(Ident, UnresolvedType)],
return_type: &FunctionReturnType,
where_clause: &[UnresolvedTraitConstraint],
trait_visibility: ItemVisibility,
func_id: FuncId,
) {
let old_generic_count = self.generics.len();
Expand All @@ -205,8 +207,9 @@ impl<'context> Elaborator<'context> {
where_clause,
return_type,
);
// Trait functions are always public
def.visibility = ItemVisibility::Public;

// Trait functions always have the same visibility as the trait they are in
def.visibility = trait_visibility;

let mut function = NoirFunction { kind, def };
self.define_function_meta(&mut function, func_id, Some(trait_id));
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@
let location = Location::new(name.span(), self.file_id);
let modifiers = FunctionModifiers {
name: name.to_string(),
visibility: ItemVisibility::Public,
visibility: trait_definition.visibility,
// TODO(Maddiaa): Investigate trait implementations with attributes see: https://github.com/noir-lang/noir/issues/2629
attributes: crate::token::Attributes::empty(),
is_unconstrained: *is_unconstrained,
Expand Down Expand Up @@ -872,7 +872,7 @@
// if it's an inline module, or the first char of a the file if it's an external module.
// - `location` will always point to the token "foo" in `mod foo` regardless of whether
// it's inline or external.
// Eventually the location put in `ModuleData` is used for codelenses about `contract`s,

Check warning on line 875 in compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (codelenses)
// so we keep using `location` so that it continues to work as usual.
let location = Location::new(mod_name.span(), mod_location.file);
let new_module = ModuleData::new(
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/hir/resolution/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ impl<'a> From<&'a ResolverError> for Diagnostic {
},
ResolverError::UnsupportedNumericGenericType(err) => err.into(),
ResolverError::TypeIsMorePrivateThenItem { typ, item, span } => {
Diagnostic::simple_warning(
Diagnostic::simple_error(
format!("Type `{typ}` is more private than item `{item}`"),
String::new(),
*span,
Expand Down
77 changes: 50 additions & 27 deletions compiler/noirc_frontend/src/hir/resolution/visibility.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::graph::CrateId;
use crate::node_interner::{FuncId, NodeInterner, StructId};
use crate::node_interner::{FuncId, NodeInterner, StructId, TraitId};
use crate::Type;

use std::collections::BTreeMap;
Expand Down Expand Up @@ -79,26 +79,47 @@ pub fn struct_member_is_visible(
visibility: ItemVisibility,
current_module_id: ModuleId,
def_maps: &BTreeMap<CrateId, CrateDefMap>,
) -> bool {
type_member_is_visible(struct_id.module_id(), visibility, current_module_id, def_maps)
}

pub fn trait_member_is_visible(
trait_id: TraitId,
visibility: ItemVisibility,
current_module_id: ModuleId,
def_maps: &BTreeMap<CrateId, CrateDefMap>,
) -> bool {
type_member_is_visible(trait_id.0, visibility, current_module_id, def_maps)
}

fn type_member_is_visible(
type_module_id: ModuleId,
visibility: ItemVisibility,
current_module_id: ModuleId,
def_maps: &BTreeMap<CrateId, CrateDefMap>,
) -> bool {
match visibility {
ItemVisibility::Public => true,
ItemVisibility::PublicCrate => {
struct_id.parent_module_id(def_maps).krate == current_module_id.krate
let type_parent_module_id =
type_module_id.parent(def_maps).expect("Expected parent module to exist");
type_parent_module_id.krate == current_module_id.krate
}
ItemVisibility::Private => {
let struct_parent_module_id = struct_id.parent_module_id(def_maps);
if struct_parent_module_id.krate != current_module_id.krate {
let type_parent_module_id =
type_module_id.parent(def_maps).expect("Expected parent module to exist");
if type_parent_module_id.krate != current_module_id.krate {
return false;
}

if struct_parent_module_id.local_id == current_module_id.local_id {
if type_parent_module_id.local_id == current_module_id.local_id {
return true;
}

let def_map = &def_maps[&current_module_id.krate];
module_descendent_of_target(
def_map,
struct_parent_module_id.local_id,
type_parent_module_id.local_id,
current_module_id.local_id,
)
}
Expand All @@ -115,35 +136,37 @@ pub fn method_call_is_visible(
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::PublicCrate | ItemVisibility::Private => {
let func_meta = interner.function_meta(&func_id);
if let Some(struct_id) = func_meta.struct_id {
return struct_member_is_visible(
struct_id,
modifiers.visibility,
current_module,
def_maps,
);
}
}
ItemVisibility::Private => {

if let Some(trait_id) = func_meta.trait_id {
return trait_member_is_visible(
trait_id,
modifiers.visibility,
current_module,
def_maps,
);
}

if object_type.is_primitive() {
let func_module = interner.function_module(func_id);
item_in_module_is_visible(
return item_in_module_is_visible(
def_maps,
current_module,
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
}
);
}

true
}
}
}
15 changes: 15 additions & 0 deletions compiler/noirc_frontend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2844,6 +2844,21 @@
assert_no_errors(src);
}

#[test]
fn trait_constraint_on_tuple_type_pub_crate() {
let src = r#"
pub(crate) trait Foo<A> {
fn foo(self, x: A) -> bool;
}

pub fn bar<T, U, V>(x: (T, U), y: V) -> bool where (T, U): Foo<V> {
x.foo(y)
}

fn main() {}"#;
assert_no_errors(src);
}

#[test]
fn incorrect_generic_count_on_struct_impl() {
let src = r#"
Expand Down Expand Up @@ -3170,7 +3185,7 @@
}

#[test]
fn dont_infer_globals_to_u32_from_type_use() {

Check warning on line 3188 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (dont)
let src = r#"
global ARRAY_LEN = 3;
global STR_LEN: _ = 2;
Expand Down Expand Up @@ -3200,7 +3215,7 @@
}

#[test]
fn dont_infer_partial_global_types() {

Check warning on line 3218 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (dont)
let src = r#"
pub global ARRAY: [Field; _] = [0; 3];
pub global NESTED_ARRAY: [[Field; _]; 3] = [[]; 3];
Expand Down Expand Up @@ -3438,7 +3453,7 @@

#[test]
fn unconditional_recursion_fail() {
let srcs = vec![

Check warning on line 3456 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (srcs)
r#"
fn main() {
main()
Expand Down Expand Up @@ -3500,7 +3515,7 @@
"#,
];

for src in srcs {

Check warning on line 3518 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (srcs)
let errors = get_program_errors(src);
assert!(
!errors.is_empty(),
Expand All @@ -3519,7 +3534,7 @@

#[test]
fn unconditional_recursion_pass() {
let srcs = vec![

Check warning on line 3537 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (srcs)
r#"
fn main() {
if false { main(); }
Expand Down Expand Up @@ -3561,7 +3576,7 @@
"#,
];

for src in srcs {

Check warning on line 3579 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (srcs)
assert_no_errors(src);
}
}
Expand Down
23 changes: 23 additions & 0 deletions compiler/noirc_frontend/src/tests/visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,29 @@ fn errors_if_pub_trait_returns_private_struct() {
assert_type_is_more_private_than_item_error(src, "Bar", "foo");
}

#[test]
fn does_not_error_if_trait_with_default_visibility_returns_struct_with_default_visibility() {
let src = r#"
struct Foo {}

trait Bar {
fn bar(self) -> Foo;
}

impl Bar for Foo {
fn bar(self) -> Foo {
self
}
}

fn main() {
let foo = Foo {};
let _ = foo.bar();
}
"#;
assert_no_errors(src);
}

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