Skip to content

Commit

Permalink
Handling use star in Semantics.
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomer-StarkWare committed Nov 5, 2024
1 parent 552e6fe commit fe47217
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 18 deletions.
52 changes: 51 additions & 1 deletion crates/cairo-lang-defs/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub trait DefsGroup:
#[salsa::interned]
fn intern_use(&self, id: UseLongId) -> UseId;
#[salsa::interned]
fn intern_global_use(&self, id: GlobalUseLongId) -> GlobalUseId;
#[salsa::interned]
fn intern_free_function(&self, id: FreeFunctionLongId) -> FreeFunctionId;
#[salsa::interned]
fn intern_impl_type_def(&self, id: ImplTypeDefLongId) -> ImplTypeDefId;
Expand Down Expand Up @@ -162,6 +164,10 @@ pub trait DefsGroup:
free_function_id: FreeFunctionId,
) -> Maybe<Option<ast::FunctionWithBody>>;
fn module_items(&self, module_id: ModuleId) -> Maybe<Arc<[ModuleItemId]>>;
fn module_global_uses(
&self,
module_id: ModuleId,
) -> Maybe<Arc<OrderedHashMap<GlobalUseId, ast::UsePathStar>>>;
/// Returns the stable ptr of the name of a module item.
fn module_item_name_stable_ptr(
&self,
Expand All @@ -174,6 +180,10 @@ pub trait DefsGroup:
) -> Maybe<Arc<OrderedHashMap<UseId, ast::UsePathLeaf>>>;
fn module_uses_ids(&self, module_id: ModuleId) -> Maybe<Arc<[UseId]>>;
fn module_use_by_id(&self, use_id: UseId) -> Maybe<Option<ast::UsePathLeaf>>;
fn module_global_use_by_id(
&self,
global_use_id: GlobalUseId,
) -> Maybe<Option<ast::UsePathStar>>;
fn module_structs(
&self,
module_id: ModuleId,
Expand Down Expand Up @@ -394,6 +404,7 @@ pub struct ModuleData {
impls: Arc<OrderedHashMap<ImplDefId, ast::ItemImpl>>,
extern_types: Arc<OrderedHashMap<ExternTypeId, ast::ItemExternType>>,
extern_functions: Arc<OrderedHashMap<ExternFunctionId, ast::ItemExternFunction>>,
global_uses: Arc<OrderedHashMap<GlobalUseId, ast::UsePathStar>>,

files: Vec<FileId>,
/// Generation info for each file. Virtual files have Some. Other files have None.
Expand Down Expand Up @@ -452,6 +463,7 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<ModuleData
let mut impls = OrderedHashMap::default();
let mut extern_types = OrderedHashMap::default();
let mut extern_functions = OrderedHashMap::default();
let mut global_uses = OrderedHashMap::default();
let mut aux_data = Vec::new();
let mut files = Vec::new();
let mut plugin_diagnostics = Vec::new();
Expand Down Expand Up @@ -487,6 +499,10 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<ModuleData
uses.insert(id, leaf);
items.push(ModuleItemId::Use(id));
}
for star in get_all_path_stars(db.upcast(), &us) {
let id = GlobalUseLongId(module_file_id, star.stable_ptr()).intern(db);
global_uses.insert(id, star);
}
}
ast::ModuleItem::FreeFunction(function) => {
let item_id =
Expand Down Expand Up @@ -568,6 +584,7 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<ModuleData
impls: impls.into(),
extern_types: extern_types.into(),
extern_functions: extern_functions.into(),
global_uses: global_uses.into(),
files,
generated_file_aux_data: aux_data,
plugin_diagnostics,
Expand Down Expand Up @@ -763,6 +780,7 @@ fn validate_attributes(
}

/// Returns all the path leaves under a given use item.
/// Notice that UsePath::Star is not returned here.
pub fn get_all_path_leaves(db: &dyn SyntaxGroup, use_item: &ast::ItemUse) -> Vec<ast::UsePathLeaf> {
let mut res = vec![];
let mut stack = vec![use_item.use_path(db)];
Expand All @@ -773,7 +791,25 @@ pub fn get_all_path_leaves(db: &dyn SyntaxGroup, use_item: &ast::ItemUse) -> Vec
ast::UsePath::Multi(use_path) => {
stack.extend(use_path.use_paths(db).elements(db).into_iter().rev())
}
ast::UsePath::Star(_) => todo!("Change function to collect `star` use as well."),
ast::UsePath::Star(_) => {}
}
}
res
}

/// Returns all the path star under a given use item.
/// Notice that UsePath::Star is not returned here.
pub fn get_all_path_stars(db: &dyn SyntaxGroup, use_item: &ast::ItemUse) -> Vec<ast::UsePathStar> {
let mut res = vec![];
let mut stack = vec![use_item.use_path(db)];
while let Some(use_path) = stack.pop() {
match use_path {
ast::UsePath::Leaf(_) => {}
ast::UsePath::Single(use_path) => stack.push(use_path.use_path(db)),
ast::UsePath::Multi(use_path) => {
stack.extend(use_path.use_paths(db).elements(db).into_iter().rev())
}
ast::UsePath::Star(use_path) => res.push(use_path),
}
}
res
Expand Down Expand Up @@ -852,6 +888,13 @@ pub fn module_use_by_id(db: &dyn DefsGroup, use_id: UseId) -> Maybe<Option<ast::
let module_uses = db.module_uses(use_id.module_file_id(db.upcast()).0)?;
Ok(module_uses.get(&use_id).cloned())
}
pub fn module_global_use_by_id(
db: &dyn DefsGroup,
global_use_id: GlobalUseId,
) -> Maybe<Option<ast::UsePathStar>> {
let module_global_uses = db.module_global_uses(global_use_id.module_file_id(db.upcast()).0)?;
Ok(module_global_uses.get(&global_use_id).cloned())
}

/// Returns all the structs of the given module.
pub fn module_structs(
Expand Down Expand Up @@ -1038,6 +1081,13 @@ fn module_items(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[ModuleIte
Ok(db.priv_module_data(module_id)?.items)
}

fn module_global_uses(
db: &dyn DefsGroup,
module_id: ModuleId,
) -> Maybe<Arc<OrderedHashMap<GlobalUseId, ast::UsePathStar>>> {
Ok(db.priv_module_data(module_id)?.global_uses)
}

fn module_item_name_stable_ptr(
db: &dyn DefsGroup,
module_id: ModuleId,
Expand Down
7 changes: 7 additions & 0 deletions crates/cairo-lang-defs/src/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,13 @@ define_top_level_language_element_id!(
lookup_intern_constant,
intern_constant
);
define_language_element_id_basic!(
GlobalUseId,
GlobalUseLongId,
ast::UsePathStar,
lookup_intern_global_use,
intern_global_use
);
define_top_level_language_element_id!(
UseId,
UseLongId,
Expand Down
15 changes: 11 additions & 4 deletions crates/cairo-lang-semantic/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use cairo_lang_defs::db::DefsGroup;
use cairo_lang_defs::diagnostic_utils::StableLocation;
use cairo_lang_defs::ids::{
ConstantId, EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, FunctionTitleId,
FunctionWithBodyId, GenericParamId, GenericTypeId, ImplAliasId, ImplConstantDefId, ImplDefId,
ImplFunctionId, ImplImplDefId, ImplItemId, ImplTypeDefId, LanguageElementId, LookupItemId,
ModuleId, ModuleItemId, ModuleTypeAliasId, StructId, TraitConstantId, TraitFunctionId, TraitId,
TraitImplId, TraitItemId, TraitTypeId, UseId, VariantId,
FunctionWithBodyId, GenericParamId, GenericTypeId, GlobalUseId, ImplAliasId, ImplConstantDefId,
ImplDefId, ImplFunctionId, ImplImplDefId, ImplItemId, ImplTypeDefId, LanguageElementId,
LookupItemId, ModuleId, ModuleItemId, ModuleTypeAliasId, StructId, TraitConstantId,
TraitFunctionId, TraitId, TraitImplId, TraitItemId, TraitTypeId, UseId, VariantId,
};
use cairo_lang_diagnostics::{Diagnostics, DiagnosticsBuilder, Maybe};
use cairo_lang_filesystem::db::{AsFilesGroupMut, FilesGroup};
Expand Down Expand Up @@ -175,6 +175,13 @@ pub trait SemanticGroup:
#[salsa::cycle(items::us::use_resolver_data_cycle)]
fn use_resolver_data(&self, use_id: UseId) -> Maybe<Arc<ResolverData>>;

// Global Use.
// ====
/// Private query to compute data about a global use.
#[salsa::invoke(items::us::priv_global_use_semantic_data)]
fn priv_global_use_semantic_data(&self, use_id: GlobalUseId)
-> Maybe<items::us::UseGlobalData>;

// Module.
// ====

Expand Down
21 changes: 20 additions & 1 deletion crates/cairo-lang-semantic/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::corelib::LiteralError;
use crate::db::SemanticGroup;
use crate::expr::inference::InferenceError;
use crate::items::feature_kind::FeatureMarkerDiagnostic;
use crate::resolve::ResolvedConcreteItem;
use crate::resolve::{ResolvedConcreteItem, ResolvedGenericItem};
use crate::types::peel_snapshots;
use crate::{ConcreteTraitId, semantic};

Expand Down Expand Up @@ -1302,6 +1302,25 @@ impl From<&ResolvedConcreteItem> for ElementKind {
}
}
}
impl From<&ResolvedGenericItem> for ElementKind {
fn from(val: &ResolvedGenericItem) -> Self {
match val {
ResolvedGenericItem::GenericConstant(_) => ElementKind::Constant,
ResolvedGenericItem::Module(_) => ElementKind::Module,
ResolvedGenericItem::GenericFunction(_) => ElementKind::Function,
ResolvedGenericItem::TraitFunction(_) => ElementKind::TraitFunction,
ResolvedGenericItem::GenericType(_) | ResolvedGenericItem::GenericTypeAlias(_) => {
ElementKind::Type
}
ResolvedGenericItem::Variant(_) => ElementKind::Variant,
ResolvedGenericItem::Trait(_) => ElementKind::Trait,
ResolvedGenericItem::Impl(_) | ResolvedGenericItem::GenericImplAlias(_) => {
ElementKind::Impl
}
ResolvedGenericItem::Variable(_) => ElementKind::Variable,
}
}
}
impl Display for ElementKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let res = match self {
Expand Down
7 changes: 4 additions & 3 deletions crates/cairo-lang-semantic/src/expr/inference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use std::ops::{Deref, DerefMut};
use cairo_lang_debug::DebugWithDb;
use cairo_lang_defs::ids::{
ConstantId, EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, GenericParamId,
ImplAliasId, ImplDefId, ImplFunctionId, ImplImplDefId, LanguageElementId, LocalVarId,
LookupItemId, MemberId, ParamId, StructId, TraitConstantId, TraitFunctionId, TraitId,
TraitImplId, TraitTypeId, VarId, VariantId,
GlobalUseId, ImplAliasId, ImplDefId, ImplFunctionId, ImplImplDefId, LanguageElementId,
LocalVarId, LookupItemId, MemberId, ParamId, StructId, TraitConstantId, TraitFunctionId,
TraitId, TraitImplId, TraitTypeId, VarId, VariantId,
};
use cairo_lang_diagnostics::{DiagnosticAdded, Maybe, skip_diagnostic};
use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
Expand Down Expand Up @@ -86,6 +86,7 @@ pub enum InferenceId {
ImplAliasImplDef(ImplAliasId),
GenericParam(GenericParamId),
GenericImplParamTrait(GenericParamId),
GlobalUseStar(GlobalUseId),
Canonical,
/// For resolving that will not be used anywhere in the semantic model.
NoContext,
Expand Down
38 changes: 38 additions & 0 deletions crates/cairo-lang-semantic/src/expr/semantic_test_data/use
Original file line number Diff line number Diff line change
Expand Up @@ -1022,3 +1022,41 @@ Block(
)

//! > expected_diagnostics

//! > ==========================================================================

//! > Testing use star

//! > test_runner_name
test_expr_semantics(expect_diagnostics: false)

//! > module_code
pub mod generic_type {
pub struct S {
pub x: u8,
}
pub enum E {
A: u8,
B: u16,
}
}

use generic_type::*;

//! > function_body

//! > expr_code
{

}

//! > expected_semantics
Block(
ExprBlock {
statements: [],
tail: None,
ty: (),
},
)

//! > expected_diagnostics
7 changes: 5 additions & 2 deletions crates/cairo-lang-semantic/src/items/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use std::sync::Arc;

use cairo_lang_defs::db::DefsGroup;
use cairo_lang_defs::ids::{
LanguageElementId, LookupItemId, ModuleId, ModuleItemId, NamedLanguageElementId, TraitId,
GlobalUseId, LanguageElementId, LookupItemId, ModuleId, ModuleItemId, NamedLanguageElementId,
TraitId,
};
use cairo_lang_diagnostics::{Diagnostics, DiagnosticsBuilder, Maybe};
use cairo_lang_syntax::attribute::structured::{Attribute, AttributeListStructurize};
Expand Down Expand Up @@ -32,6 +33,7 @@ pub struct ModuleItemInfo {
pub struct ModuleSemanticData {
/// The items in the module without duplicates.
pub items: OrderedHashMap<SmolStr, ModuleItemInfo>,
pub global_uses: Vec<GlobalUseId>,
pub diagnostics: Diagnostics<SemanticDiagnostic>,
}

Expand Down Expand Up @@ -110,7 +112,8 @@ pub fn priv_module_semantic_data(
);
}
}
Ok(Arc::new(ModuleSemanticData { items, diagnostics: diagnostics.build() }))
let global_uses = db.module_global_uses(module_id)?.keys().copied().collect::<Vec<_>>();
Ok(Arc::new(ModuleSemanticData { items, global_uses, diagnostics: diagnostics.build() }))
}

pub fn module_item_by_name(
Expand Down
63 changes: 56 additions & 7 deletions crates/cairo-lang-semantic/src/items/us.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::sync::Arc;

use cairo_lang_defs::ids::{LanguageElementId, LookupItemId, ModuleItemId, UseId};
use cairo_lang_defs::ids::{
GlobalUseId, LanguageElementId, LookupItemId, ModuleId, ModuleItemId, UseId,
};
use cairo_lang_diagnostics::{Diagnostics, Maybe, ToMaybe};
use cairo_lang_proc_macros::DebugWithDb;
use cairo_lang_syntax::node::db::SyntaxGroup;
Expand All @@ -12,7 +14,9 @@ use cairo_lang_utils::Upcast;
use crate::SemanticDiagnostic;
use crate::db::SemanticGroup;
use crate::diagnostic::SemanticDiagnosticKind::*;
use crate::diagnostic::{NotFoundItemType, SemanticDiagnostics, SemanticDiagnosticsBuilder};
use crate::diagnostic::{
ElementKind, NotFoundItemType, SemanticDiagnostics, SemanticDiagnosticsBuilder,
};
use crate::expr::inference::InferenceId;
use crate::resolve::{ResolvedGenericItem, Resolver, ResolverData};

Expand Down Expand Up @@ -49,6 +53,49 @@ pub fn priv_use_semantic_data(db: &dyn SemanticGroup, use_id: UseId) -> Maybe<Us
Ok(UseData { diagnostics: diagnostics.build(), resolved_item, resolver_data })
}

/// Query implementation of [crate::db::SemanticGroup::priv_global_use_semantic_data].
pub fn priv_global_use_semantic_data(
db: &dyn SemanticGroup,
global_use_id: GlobalUseId,
) -> Maybe<UseGlobalData> {
let module_file_id = global_use_id.module_file_id(db.upcast());
let mut diagnostics = SemanticDiagnostics::default();
let inference_id = InferenceId::GlobalUseStar(global_use_id);
let star_ast = ast::UsePath::Star(db.module_global_use_by_id(global_use_id)?.to_maybe()?);
let mut resolver = Resolver::new(db, module_file_id, inference_id);

let item = star_ast.get_item(db.upcast());
let segments = get_use_path_segments(db.upcast(), star_ast.clone())?;
resolver.set_feature_config(&global_use_id, &item, &mut diagnostics);
let resolved_item = resolver.resolve_generic_path(
&mut diagnostics,
segments,
NotFoundItemType::Identifier,
None,
);
let resolver_data = Arc::new(resolver.data);
let imported_module = resolved_item.and_then(|item| {
if let ResolvedGenericItem::Module(module_id) = item {
Ok(module_id)
} else {
Err(diagnostics.report(&star_ast, UnexpectedElement {
expected: vec![ElementKind::Module],
actual: (&item).into(),
}))
}
});

Ok(UseGlobalData { diagnostics: diagnostics.build(), imported_module, resolver_data })
}

#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
#[debug_db(dyn SemanticGroup + 'static)]
pub struct UseGlobalData {
diagnostics: Diagnostics<SemanticDiagnostic>,
imported_module: Maybe<ModuleId>,
resolver_data: Arc<ResolverData>,
}

/// Returns the segments that are the parts of the use path.
///
/// The segments are returned in the order they appear in the use path.
Expand All @@ -61,13 +108,15 @@ pub fn get_use_path_segments(
db: &dyn SyntaxGroup,
use_path: ast::UsePath,
) -> Maybe<Vec<ast::PathSegment>> {
let mut rev_segments = vec![match &use_path {
ast::UsePath::Leaf(use_ast) => use_ast.ident(db),
ast::UsePath::Single(use_ast) => use_ast.ident(db),
ast::UsePath::Multi(_) | ast::UsePath::Star(_) => {
let mut rev_segments = vec![];
match &use_path {
ast::UsePath::Leaf(use_ast) => rev_segments.push(use_ast.ident(db)),
ast::UsePath::Single(use_ast) => rev_segments.push(use_ast.ident(db)),
ast::UsePath::Star(_) => {}
ast::UsePath::Multi(_) => {
panic!("Only `UsePathLeaf` and `UsePathSingle` are supported.")
}
}];
}
let mut current_use_path = use_path;
while let Some(parent_use_path) = get_parent_single_use_path(db, &current_use_path) {
rev_segments.push(parent_use_path.ident(db));
Expand Down

0 comments on commit fe47217

Please sign in to comment.