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: visibility for impl functions #6179

Merged
merged 12 commits into from
Oct 3, 2024
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,7 @@ impl<'context> Elaborator<'context> {
// object types in each method overlap or not. If they do, we issue an error.
// If not, that is specialization which is allowed.
let name = method.name_ident().clone();
if module.declare_function(name, ItemVisibility::Public, *method_id).is_err() {
if module.declare_function(name, method.def.visibility, *method_id).is_err() {
let existing = module.find_func_with_name(method.name_ident()).expect(
"declare_function should only error if there is an existing function",
);
Expand Down
8 changes: 7 additions & 1 deletion compiler/noirc_frontend/src/elaborator/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,13 @@ impl<'context> Elaborator<'context> {
}

fn resolve_path_in_module(&mut self, path: Path, module_id: ModuleId) -> PathResolutionResult {
let resolver = StandardPathResolver::new(module_id);
let self_type_module_id = if let Some(Type::Struct(struct_type, _)) = &self.self_type {
Some(struct_type.borrow().id.module_id())
} else {
None
};

let resolver = StandardPathResolver::new(module_id, self_type_module_id);

if !self.interner.lsp_mode {
return resolver.resolve(
Expand Down
3 changes: 2 additions & 1 deletion compiler/noirc_frontend/src/hir/comptime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ fn interpret_helper(src: &str) -> Result<Value, InterpreterError> {
location,
Vec::new(),
Vec::new(),
false,
false, // is contract
false, // is struct
)));
assert_eq!(root, module_id);

Expand Down
2 changes: 2 additions & 0 deletions compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ fn inject_prelude(
if let Ok(PathResolution { module_def_id, error }) = path_resolver::resolve_path(
&context.def_maps,
ModuleId { krate: crate_id, local_id: crate_root },
None,
path,
&mut context.def_interner.usage_tracker,
&mut None,
Expand All @@ -564,6 +565,7 @@ fn inject_prelude(
ImportDirective {
visibility: ItemVisibility::Private,
module_id: crate_root,
self_type_module_id: None,
path: Path { segments, kind: PathKind::Plain, span: Span::default() },
alias: None,
is_prelude: true,
Expand Down
26 changes: 20 additions & 6 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
collector.def_collector.imports.push(ImportDirective {
visibility: import.visibility,
module_id: collector.module_id,
self_type_module_id: None,
path: import.path,
alias: import.alias,
is_prelude: false,
Expand Down Expand Up @@ -385,7 +386,8 @@
Vec::new(),
Vec::new(),
false,
false,
false, // is contract
false, // is struct
) {
Ok(module_id) => TraitId(ModuleId { krate, local_id: module_id.local_id }),
Err(error) => {
Expand Down Expand Up @@ -618,6 +620,7 @@
submodule.contents.inner_attributes.clone(),
true,
submodule.is_contract,
false, // is struct
) {
Ok(child) => {
self.collect_attributes(
Expand Down Expand Up @@ -717,7 +720,8 @@
mod_decl.outer_attributes.clone(),
ast.inner_attributes.clone(),
true,
false,
false, // is contract
false, // is struct
) {
Ok(child_mod_id) => {
self.collect_attributes(
Expand Down Expand Up @@ -769,6 +773,7 @@
inner_attributes: Vec<SecondaryAttribute>,
add_to_parent_scope: bool,
is_contract: bool,
is_struct: bool,
) -> Result<ModuleId, DefCollectorErrorKind> {
push_child_module(
&mut context.def_interner,
Expand All @@ -781,6 +786,7 @@
inner_attributes,
add_to_parent_scope,
is_contract,
is_struct,
)
}

Expand Down Expand Up @@ -816,6 +822,7 @@
inner_attributes: Vec<SecondaryAttribute>,
add_to_parent_scope: bool,
is_contract: bool,
is_struct: bool,
) -> Result<ModuleId, DefCollectorErrorKind> {
// Note: the difference between `location` and `mod_location` is:
// - `mod_location` will point to either the token "foo" in `mod foo { ... }`
Expand All @@ -823,10 +830,16 @@
// - `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,
// so we keep using `location` so that it continues to work as usual.

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (codelenses)
let location = Location::new(mod_name.span(), mod_location.file);
let new_module =
ModuleData::new(Some(parent), location, outer_attributes, inner_attributes, is_contract);
let new_module = ModuleData::new(
Some(parent),
location,
outer_attributes,
inner_attributes,
is_contract,
is_struct,
);

let module_id = def_map.modules.insert(new_module);
let modules = &mut def_map.modules;
Expand Down Expand Up @@ -961,8 +974,9 @@
location,
Vec::new(),
Vec::new(),
false,
false,
false, // add to parent scope
false, // is contract
true, // is struct
) {
Ok(module_id) => {
interner.new_struct(&unresolved, resolved_generics, krate, module_id.local_id, file_id)
Expand Down
3 changes: 2 additions & 1 deletion compiler/noirc_frontend/src/hir/def_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ impl CrateDefMap {
location,
Vec::new(),
ast.inner_attributes.clone(),
false,
false, // is contract
false, // is struct
));

let def_map = CrateDefMap {
Expand Down
5 changes: 5 additions & 0 deletions compiler/noirc_frontend/src/hir/def_map/module_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ pub struct ModuleData {
/// True if this module is a `contract Foo { ... }` module containing contract functions
pub is_contract: bool,

/// True if this module is actually a struct
pub is_struct: bool,

pub attributes: Vec<SecondaryAttribute>,
}

Expand All @@ -36,6 +39,7 @@ impl ModuleData {
outer_attributes: Vec<SecondaryAttribute>,
inner_attributes: Vec<SecondaryAttribute>,
is_contract: bool,
is_struct: bool,
) -> ModuleData {
let mut attributes = outer_attributes;
attributes.extend(inner_attributes);
Expand All @@ -47,6 +51,7 @@ impl ModuleData {
definitions: ItemScope::default(),
location,
is_contract,
is_struct,
attributes,
}
}
Expand Down
60 changes: 38 additions & 22 deletions compiler/noirc_frontend/src/hir/resolution/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::graph::CrateId;
use crate::hir::def_collector::dc_crate::CompilationError;
use crate::node_interner::ReferenceId;
use crate::usage_tracker::UsageTracker;

use std::collections::BTreeMap;

use crate::ast::{Ident, ItemVisibility, Path, PathKind, PathSegment};
Expand All @@ -16,6 +17,7 @@ use super::errors::ResolverError;
pub struct ImportDirective {
pub visibility: ItemVisibility,
pub module_id: LocalModuleId,
pub self_type_module_id: Option<ModuleId>,
pub path: Path,
pub alias: Option<Ident>,
pub is_prelude: bool,
Expand Down Expand Up @@ -92,18 +94,15 @@ pub fn resolve_import(
path_references: &mut Option<&mut Vec<ReferenceId>>,
) -> Result<ResolvedImport, PathResolutionError> {
let module_scope = import_directive.module_id;
let NamespaceResolution {
module_id: resolved_module,
namespace: resolved_namespace,
mut error,
} = resolve_path_to_ns(
import_directive,
crate_id,
crate_id,
def_maps,
usage_tracker,
path_references,
)?;
let NamespaceResolution { module_id: resolved_module, namespace: resolved_namespace, error } =
resolve_path_to_ns(
import_directive,
crate_id,
crate_id,
def_maps,
usage_tracker,
path_references,
)?;

let name = resolve_path_name(import_directive);

Expand All @@ -113,14 +112,16 @@ pub fn resolve_import(
.map(|(_, visibility, _)| visibility)
.expect("Found empty namespace");

error = error.or_else(|| {
if can_reference_module_id(
def_maps,
crate_id,
import_directive.module_id,
resolved_module,
visibility,
) {
let error = error.or_else(|| {
if import_directive.self_type_module_id == Some(resolved_module)
|| can_reference_module_id(
def_maps,
crate_id,
import_directive.module_id,
resolved_module,
visibility,
)
{
None
} else {
Some(PathResolutionError::Private(name.clone()))
Expand Down Expand Up @@ -408,6 +409,7 @@ fn resolve_external_dep(
let dep_directive = ImportDirective {
visibility: ItemVisibility::Private,
module_id: dep_module.local_id,
self_type_module_id: directive.self_type_module_id,
path,
alias: directive.alias.clone(),
is_prelude: false,
Expand Down Expand Up @@ -442,11 +444,15 @@ pub fn can_reference_module_id(
ItemVisibility::PublicCrate => same_crate,
ItemVisibility::Private => {
same_crate
&& module_descendent_of_target(
&& (module_descendent_of_target(
target_crate_def_map,
target_module.local_id,
current_module,
)
) || module_is_parent_of_struct_module(
target_crate_def_map,
current_module,
target_module.local_id,
))
}
}
}
Expand All @@ -466,3 +472,13 @@ fn module_descendent_of_target(
.parent
.map_or(false, |parent| module_descendent_of_target(def_map, target, parent))
}

/// Returns true if `target` is a struct and its parent is `current`.
fn module_is_parent_of_struct_module(
def_map: &CrateDefMap,
current: LocalModuleId,
target: LocalModuleId,
) -> bool {
let module_data = &def_map.modules[target.0];
module_data.is_struct && module_data.parent == Some(current)
}
18 changes: 15 additions & 3 deletions compiler/noirc_frontend/src/hir/resolution/path_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::import::{resolve_import, ImportDirective, PathResolution, PathResolut
use crate::ast::{ItemVisibility, Path};
use crate::node_interner::ReferenceId;
use crate::usage_tracker::UsageTracker;

use std::collections::BTreeMap;

use crate::graph::CrateId;
Expand All @@ -28,11 +29,13 @@ pub trait PathResolver {
pub struct StandardPathResolver {
// Module that we are resolving the path in
module_id: ModuleId,
// The module of the self type, if any (for example, the ModuleId of a struct)
self_type_module_id: Option<ModuleId>,
}

impl StandardPathResolver {
pub fn new(module_id: ModuleId) -> StandardPathResolver {
Self { module_id }
pub fn new(module_id: ModuleId, self_type_module_id: Option<ModuleId>) -> StandardPathResolver {
Self { module_id, self_type_module_id }
}
}

Expand All @@ -44,7 +47,14 @@ impl PathResolver for StandardPathResolver {
usage_tracker: &mut UsageTracker,
path_references: &mut Option<&mut Vec<ReferenceId>>,
) -> PathResolutionResult {
resolve_path(def_maps, self.module_id, path, usage_tracker, path_references)
resolve_path(
def_maps,
self.module_id,
self.self_type_module_id,
path,
usage_tracker,
path_references,
)
}

fn local_module_id(&self) -> LocalModuleId {
Expand All @@ -61,6 +71,7 @@ impl PathResolver for StandardPathResolver {
pub fn resolve_path(
def_maps: &BTreeMap<CrateId, CrateDefMap>,
module_id: ModuleId,
self_type_module_id: Option<ModuleId>,
path: Path,
usage_tracker: &mut UsageTracker,
path_references: &mut Option<&mut Vec<ReferenceId>>,
Expand All @@ -69,6 +80,7 @@ pub fn resolve_path(
let import = ImportDirective {
visibility: ItemVisibility::Private,
module_id: module_id.local_id,
self_type_module_id,
path,
alias: None,
is_prelude: false,
Expand Down
3 changes: 2 additions & 1 deletion compiler/noirc_frontend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ pub(crate) fn get_program(src: &str) -> (ParsedModule, Context, Vec<(Compilation
location,
Vec::new(),
inner_attributes.clone(),
false,
false, // is contract
false, // is struct
));

let def_map = CrateDefMap {
Expand Down
6 changes: 3 additions & 3 deletions compiler/noirc_frontend/src/tests/turbofish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ fn turbofish_numeric_generic_nested_call() {
}

impl<T> Foo<T> {
fn static_method<let N: u32>() -> [u8; N] {
pub fn static_method<let N: u32>() -> [u8; N] {
[0; N]
}

fn impl_method<let N: u32>(self) -> [T; N] {
pub fn impl_method<let N: u32>(self) -> [T; N] {
[self.a; N]
}
}
Expand Down Expand Up @@ -108,7 +108,7 @@ fn turbofish_in_middle_of_variable_unsupported_yet() {
}

impl <T> Foo<T> {
fn new(x: T) -> Self {
pub fn new(x: T) -> Self {
Foo { x }
}
}
Expand Down
Loading
Loading