Skip to content

Commit

Permalink
Refactoring module global uses to db (#6762)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomer-StarkWare authored Nov 28, 2024
1 parent abf7c20 commit 0d9de39
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 71 deletions.
5 changes: 4 additions & 1 deletion crates/cairo-lang-semantic/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::items::trt::{
ConcreteTraitGenericFunctionId, ConcreteTraitId, TraitItemConstantData, TraitItemImplData,
TraitItemTypeData,
};
use crate::items::us::SemanticUseEx;
use crate::items::us::{ImportedModules, SemanticUseEx};
use crate::items::visibility::Visibility;
use crate::plugin::AnalyzerPlugin;
use crate::resolve::{ResolvedConcreteItem, ResolvedGenericItem, ResolverData};
Expand Down Expand Up @@ -194,6 +194,9 @@ pub trait SemanticGroup:
&self,
global_use_id: GlobalUseId,
) -> Diagnostics<SemanticDiagnostic>;
/// Private query to compute the imported modules of a module, using global uses.
#[salsa::invoke(items::us::priv_module_use_star_modules)]
fn priv_module_use_star_modules(&self, module_id: ModuleId) -> Arc<ImportedModules>;

// Module.
// ====
Expand Down
63 changes: 62 additions & 1 deletion crates/cairo-lang-semantic/src/items/us.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ use cairo_lang_syntax::node::helpers::UsePathEx;
use cairo_lang_syntax::node::kind::SyntaxKind;
use cairo_lang_syntax::node::{TypedSyntaxNode, ast};
use cairo_lang_utils::Upcast;
use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;

use super::module::get_module_global_uses;
use super::visibility::peek_visible_in;
use crate::SemanticDiagnostic;
use crate::db::SemanticGroup;
use crate::diagnostic::SemanticDiagnosticKind::*;
Expand Down Expand Up @@ -237,7 +241,7 @@ pub fn priv_global_use_semantic_data_cycle(
let global_use_ast = db.module_global_use_by_id(*global_use_id)?.to_maybe()?;
let star_ast = ast::UsePath::Star(db.module_global_use_by_id(*global_use_id)?.to_maybe()?);
let segments = get_use_path_segments(db.upcast(), star_ast)?;
let err = if cycle.participant_keys().count() <= 2 && segments.len() == 1 {
let err = if cycle.participant_keys().count() <= 3 && segments.len() == 1 {
// `use bad_name::*`, will attempt to find `bad_name` in the current module's global
// uses, but which includes itself - but we don't want to report a cycle in this case.
diagnostics.report(
Expand All @@ -249,3 +253,60 @@ pub fn priv_global_use_semantic_data_cycle(
};
Ok(UseGlobalData { diagnostics: diagnostics.build(), imported_module: Err(err) })
}

/// The modules that are imported by a module, using global uses.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImportedModules {
/// The imported modules that have a path where each step is visible by the previous module.
pub accessible: OrderedHashSet<(ModuleId, ModuleId)>,
// TODO(Tomer-StarkWare): consider changing from all_modules to inaccessible_modules
/// All the imported modules.
pub all: OrderedHashSet<ModuleId>,
}
/// Returns the modules that are imported with `use *` in the current module.
/// Query implementation of [crate::db::SemanticGroup::priv_module_use_star_modules].
pub fn priv_module_use_star_modules(
db: &dyn SemanticGroup,
module_id: ModuleId,
) -> Arc<ImportedModules> {
let mut visited = UnorderedHashSet::<_>::default();
let mut stack = vec![(module_id, module_id)];
let mut accessible_modules = OrderedHashSet::default();
// Iterate over all modules that are imported through `use *`, and are accessible from the
// current module.
while let Some((user_module, containing_module)) = stack.pop() {
if !visited.insert((user_module, containing_module)) {
continue;
}
let Ok(glob_uses) = get_module_global_uses(db, containing_module) else {
continue;
};
for (glob_use, item_visibility) in glob_uses.iter() {
let Ok(module_id_found) = db.priv_global_use_imported_module(*glob_use) else {
continue;
};
if peek_visible_in(db.upcast(), *item_visibility, containing_module, user_module) {
stack.push((containing_module, module_id_found));
accessible_modules.insert((containing_module, module_id_found));
}
}
}
let mut visited = UnorderedHashSet::<_>::default();
let mut stack = vec![module_id];
let mut all_modules = OrderedHashSet::default();
// Iterate over all modules that are imported through `use *`.
while let Some(curr_module_id) = stack.pop() {
if !visited.insert(curr_module_id) {
continue;
}
all_modules.insert(curr_module_id);
let Ok(glob_uses) = get_module_global_uses(db, curr_module_id) else { continue };
for glob_use in glob_uses.keys() {
let Ok(module_id_found) = db.priv_global_use_imported_module(*glob_use) else {
continue;
};
stack.push(module_id_found);
}
}
Arc::new(ImportedModules { accessible: accessible_modules, all: all_modules })
}
77 changes: 8 additions & 69 deletions crates/cairo-lang-semantic/src/resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode, ast};
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
use cairo_lang_utils::{Intern, LookupIntern, extract_matches, require, try_extract_matches};
pub use item::{ResolvedConcreteItem, ResolvedGenericItem};
use itertools::Itertools;
Expand Down Expand Up @@ -47,12 +46,11 @@ use crate::items::generics::generic_params_to_args;
use crate::items::imp::{
ConcreteImplId, ConcreteImplLongId, ImplImplId, ImplLongId, ImplLookupContext,
};
use crate::items::module::{ModuleItemInfo, get_module_global_uses};
use crate::items::module::ModuleItemInfo;
use crate::items::trt::{
ConcreteTraitConstantLongId, ConcreteTraitGenericFunctionLongId, ConcreteTraitId,
ConcreteTraitImplLongId, ConcreteTraitLongId, ConcreteTraitTypeId,
};
use crate::items::visibility::peek_visible_in;
use crate::items::{TraitOrImplContext, visibility};
use crate::substitution::{GenericSubstitution, SemanticRewriter, SubstitutionRewriter};
use crate::types::{ImplTypeId, are_coupons_enabled, resolve_type};
Expand Down Expand Up @@ -246,15 +244,6 @@ enum UseStarResult {
ItemNotVisible(ModuleItemId, Vec<ModuleId>),
}

/// The modules that are imported by a module, using global uses.
struct ImportedModules {
/// The imported modules that have a path where each step is visible by the previous module.
accessible_modules: OrderedHashSet<(ModuleId, ModuleId)>,
// TODO(Tomer-StarkWare): consider changing from all_modules to inaccessible_modules
/// All the imported modules.
all_modules: OrderedHashSet<ModuleId>,
}

/// A trait for things that can be interpreted as a path of segments.
pub trait AsSegments {
fn to_segments(self, db: &dyn SyntaxGroup) -> Vec<ast::PathSegment>;
Expand Down Expand Up @@ -1139,27 +1128,27 @@ impl<'db> Resolver<'db> {
) -> UseStarResult {
let mut item_info = None;
let mut module_items_found: OrderedHashSet<ModuleItemId> = OrderedHashSet::default();
let imported_modules = self.module_use_star_modules(module_id);
let imported_modules = self.db.priv_module_use_star_modules(module_id);
let mut containing_modules = vec![];
let mut is_accessible = false;
for (star_module_id, item_module_id) in imported_modules.accessible_modules {
for (star_module_id, item_module_id) in &imported_modules.accessible {
if let Some(inner_item_info) =
self.resolve_item_in_imported_module(item_module_id, identifier)
self.resolve_item_in_imported_module(*item_module_id, identifier)
{
item_info = Some(inner_item_info.clone());
is_accessible |=
self.is_item_visible(item_module_id, &inner_item_info, star_module_id)
self.is_item_visible(*item_module_id, &inner_item_info, *star_module_id)
&& self.is_item_feature_usable(&inner_item_info);
module_items_found.insert(inner_item_info.item_id);
}
}
for star_module_id in imported_modules.all_modules {
for star_module_id in &imported_modules.all {
if let Some(inner_item_info) =
self.resolve_item_in_imported_module(star_module_id, identifier)
self.resolve_item_in_imported_module(*star_module_id, identifier)
{
item_info = Some(inner_item_info.clone());
module_items_found.insert(inner_item_info.item_id);
containing_modules.push(star_module_id);
containing_modules.push(*star_module_id);
}
}
if module_items_found.len() > 1 {
Expand Down Expand Up @@ -1192,56 +1181,6 @@ impl<'db> Resolver<'db> {
None
}

/// Returns the modules that are imported with `use *` in the current module.
fn module_use_star_modules(&self, module_id: ModuleId) -> ImportedModules {
let mut visited = UnorderedHashSet::<_>::default();
let mut stack = vec![(module_id, module_id)];
let mut accessible_modules = OrderedHashSet::default();
// Iterate over all modules that are imported through `use *`, and are accessible from the
// current module.
while let Some((user_module, containing_module)) = stack.pop() {
if !visited.insert((user_module, containing_module)) {
continue;
}
let Ok(glob_uses) = get_module_global_uses(self.db, containing_module) else {
continue;
};
for (glob_use, item_visibility) in glob_uses.iter() {
let Ok(module_id_found) = self.db.priv_global_use_imported_module(*glob_use) else {
continue;
};
if peek_visible_in(
self.db.upcast(),
*item_visibility,
containing_module,
user_module,
) {
stack.push((containing_module, module_id_found));
accessible_modules.insert((containing_module, module_id_found));
}
}
}

let mut visited = UnorderedHashSet::<_>::default();
let mut stack = vec![module_id];
let mut all_modules = OrderedHashSet::default();
// Iterate over all modules that are imported through `use *`.
while let Some(curr_module_id) = stack.pop() {
if !visited.insert(curr_module_id) {
continue;
}
all_modules.insert(curr_module_id);
let Ok(glob_uses) = get_module_global_uses(self.db, curr_module_id) else { continue };
for glob_use in glob_uses.keys() {
let Ok(module_id_found) = self.db.priv_global_use_imported_module(*glob_use) else {
continue;
};
stack.push(module_id_found);
}
}
ImportedModules { accessible_modules, all_modules }
}

/// Given the current resolved item, resolves the next segment.
fn resolve_path_next_segment_generic(
&mut self,
Expand Down

0 comments on commit 0d9de39

Please sign in to comment.