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 all 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 @@ -3168,7 +3183,7 @@
use CompilationError::TypeError;
assert!(matches!(&errors[0].0, TypeError(TypeCheckError::NoMatchingImplFound { .. })));
}

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (dont)
#[test]
fn dont_infer_globals_to_u32_from_type_use() {
let src = r#"
Expand Down Expand Up @@ -3198,7 +3213,7 @@
));
}
}

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (dont)
#[test]
fn dont_infer_partial_global_types() {
let src = r#"
Expand Down Expand Up @@ -3436,7 +3451,7 @@
));
}

#[test]

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (srcs)
fn unconditional_recursion_fail() {
let srcs = vec![
r#"
Expand Down Expand Up @@ -3498,7 +3513,7 @@
sum
}
"#,
];

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (srcs)

for src in srcs {
let errors = get_program_errors(src);
Expand All @@ -3517,7 +3532,7 @@
}
}

#[test]

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (srcs)
fn unconditional_recursion_pass() {
let srcs = vec![
r#"
Expand Down Expand Up @@ -3559,7 +3574,7 @@
foo();
}
"#,
];

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (srcs)

for src in 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
2 changes: 2 additions & 0 deletions docs/docs/noir/concepts/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -582,3 +582,5 @@ pub trait Trait {}
// This trait alias is now public
pub trait Baz = Foo + Bar;
```

Trait methods have the same visibility as the trait they are in.
Loading