From 2c81f5efc3ddc3c0405d36f7a50f272de30e473a Mon Sep 17 00:00:00 2001 From: Ori Ziv Date: Sun, 18 Aug 2024 12:17:07 +0300 Subject: [PATCH] Made calculating following files recursive. commit-id:0ea9ed50 --- crates/cairo-lang-defs/src/db.rs | 282 ++++++++++-------- .../cairo-lang-semantic/src/expr/compute.rs | 11 +- crates/cairo-lang-starknet/src/abi.rs | 4 +- crates/cairo-lang-starknet/src/contract.rs | 14 +- 4 files changed, 163 insertions(+), 148 deletions(-) diff --git a/crates/cairo-lang-defs/src/db.rs b/crates/cairo-lang-defs/src/db.rs index 58d34fb66e6..2a9b10a54e3 100644 --- a/crates/cairo-lang-defs/src/db.rs +++ b/crates/cairo-lang-defs/src/db.rs @@ -125,6 +125,12 @@ pub trait DefsGroup: // Module level resolving. fn priv_module_data(&self, module_id: ModuleId) -> Maybe; + // Returns the information about sub-files generated by the file in the module. + fn priv_module_sub_files( + &self, + module_id: ModuleId, + file_id: FileId, + ) -> Maybe>; fn module_submodules( &self, module_id: ModuleId, @@ -219,10 +225,10 @@ pub trait DefsGroup: extern_function_id: ExternFunctionId, ) -> Maybe>; fn module_ancestors(&self, module_id: ModuleId) -> OrderedHashSet; - fn module_generated_file_infos( + fn module_generated_file_aux_data( &self, module_id: ModuleId, - ) -> Maybe]>>; + ) -> Maybe]>>; fn module_plugin_diagnostics( &self, module_id: ModuleId, @@ -354,14 +360,6 @@ fn file_modules(db: &dyn DefsGroup, file_id: FileId) -> Maybe> { Ok(db.priv_file_to_module_mapping().get(&file_id).to_maybe()?.clone().into()) } -/// Information about the generation of a virtual file. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct GeneratedFileInfo { - pub aux_data: Option, - /// The module and file index from which the current file was generated. - pub origin: ModuleFileId, -} - #[derive(Clone, Debug, PartialEq, Eq)] pub struct ModuleData { /// The list of IDs of all items in the module. Each ID here is guaranteed to be a key in one @@ -384,49 +382,48 @@ pub struct ModuleData { files: Vec, /// Generation info for each file. Virtual files have Some. Other files have None. - generated_file_infos: Vec>, + generated_file_aux_data: Vec>, plugin_diagnostics: Vec<(ModuleFileId, PluginDiagnostic)>, } -// TODO(spapini): Make this private. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PrivModuleFileData { + /// The files generated by plugins running on items. + pub files: Vec, + /// The aux data per such file. + pub aux_data: Vec>, + /// The items not filtered out by plugins. + pub items: Vec, + /// The diagnostics generated by the plugins. + pub plugin_diagnostics: Vec, +} + fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe { let syntax_db = db.upcast(); let module_file = db.module_main_file(module_id)?; + let main_file_aux_data = if let ModuleId::Submodule(submodule_id) = module_id { + let parent_module_data = db.priv_module_data(submodule_id.parent_module(db))?; + let item_module_ast = &parent_module_data.submodules[&submodule_id]; + if matches!(item_module_ast.body(syntax_db), MaybeModuleBody::Some(_)) { + // TODO(spapini): Diagnostics in this module that get mapped to parent module + // should lie in that modules ModuleData, or somehow collected by its + // diagnostics collector function. - let file_syntax = db.file_module_syntax(module_file)?; - let mut main_file_info: Option = None; - let item_asts = match module_id { - ModuleId::CrateRoot(_) => file_syntax.items(syntax_db), - ModuleId::Submodule(submodule_id) => { - let parent_module_data = db.priv_module_data(submodule_id.parent_module(db))?; - let item_module_ast = &parent_module_data.submodules[&submodule_id]; - - match item_module_ast.body(syntax_db) { - MaybeModuleBody::Some(body) => { - // TODO(spapini): Diagnostics in this module that get mapped to parent module - // should lie in that modules ModuleData, or somehow collected by its - // diagnostics collector function. - - // If this is an inline module, copy its generation file info from the parent - // module, from the file where this submodule was defined. - main_file_info = parent_module_data - .generated_file_infos - .into_iter() - .nth(submodule_id.file_index(db).0) - .unwrap(); - body.items(syntax_db) - } - MaybeModuleBody::None(_) => file_syntax.items(syntax_db), - } + // If this is an inline module, copy its generation file info from the parent + // module, from the file where this submodule was defined. + parent_module_data + .generated_file_aux_data + .into_iter() + .nth(submodule_id.file_index(db).0) + .unwrap() + } else { + None } + } else { + None }; - - let allowed_attributes = db.allowed_attributes(); - // TODO(orizi): Actually extract the allowed features per module. - let allowed_features = Default::default(); - - let mut module_queue = VecDeque::new(); - module_queue.push_back((module_file, item_asts)); + let mut file_queue = VecDeque::new(); + file_queue.push_back(module_file); let mut constants = OrderedHashMap::default(); let mut submodules = OrderedHashMap::default(); let mut uses = OrderedHashMap::default(); @@ -439,79 +436,25 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe { let item_id = ConstantLongId(module_file_id, constant.stable_ptr()).intern(db); constants.insert(item_id, constant); @@ -611,27 +554,112 @@ fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe Maybe> { + let syntax_db = db.upcast(); + let module_main_file = db.module_main_file(module_id)?; + let file_syntax = db.file_module_syntax(file_id)?; + let item_asts = if module_main_file == file_id { + if let ModuleId::Submodule(submodule_id) = module_id { + let data = db.priv_module_data(submodule_id.parent_module(db))?; + if let MaybeModuleBody::Some(body) = data.submodules[&submodule_id].body(db.upcast()) { + Some(body.items(syntax_db)) + } else { + None + } + } else { + None + } + } else { + None + } + .unwrap_or_else(|| file_syntax.items(syntax_db)); + + let allowed_attributes = db.allowed_attributes(); + // TODO(orizi): Actually extract the allowed features per module. + let allowed_features = Default::default(); + + let crate_id = module_id.owning_crate(db); + let cfg_set = db + .crate_config(crate_id) + .and_then(|cfg| cfg.settings.cfg_set.map(Arc::new)) + .unwrap_or(db.cfg_set()); + let edition = db + .crate_config(module_id.owning_crate(db)) + .map(|cfg| cfg.settings.edition) + .unwrap_or_default(); + let metadata = MacroPluginMetadata { + cfg_set: &cfg_set, + declared_derives: &db.declared_derives(), + allowed_features: &allowed_features, + edition, + }; + + let mut files = Vec::new(); + let mut aux_data = Vec::new(); + let mut items = Vec::new(); + let mut plugin_diagnostics = Vec::new(); + for item_ast in item_asts.elements(syntax_db) { + let mut remove_original_item = false; + // Iterate the plugins by their order. The first one to change something (either + // generate new code, remove the original code, or both), breaks the loop. If more + // plugins might have act on the item, they can do it on the generated code. + for plugin in db.macro_plugins() { + let result = plugin.generate_code(db.upcast(), item_ast.clone(), &metadata); + plugin_diagnostics.extend(result.diagnostics); + if result.remove_original_item { + remove_original_item = true; + } + + if let Some(generated) = result.code { + files.push( + FileLongId::Virtual(VirtualFile { + parent: Some(file_id), + name: generated.name, + content: generated.content.into(), + code_mappings: generated.code_mappings.into(), + kind: FileKind::Module, + }) + .intern(db), + ); + aux_data.push(generated.aux_data); + } + if remove_original_item { + break; + } + } + if remove_original_item { + // Don't add the original item to the module data. + continue; + } + validate_attributes(syntax_db, &allowed_attributes, &item_ast, &mut plugin_diagnostics); + items.push(item_ast); + } + let res = PrivModuleFileData { files, aux_data, items, plugin_diagnostics }; + Ok(res.into()) +} + /// Validates that all attributes on the given item are in the allowed set or adds diagnostics. pub fn validate_attributes_flat( db: &dyn SyntaxGroup, allowed_attributes: &OrderedHashSet, - module_file_id: ModuleFileId, item: &impl QueryAttrs, - plugin_diagnostics: &mut Vec<(ModuleFileId, PluginDiagnostic)>, + plugin_diagnostics: &mut Vec, ) { for attr in item.attributes_elements(db) { if !allowed_attributes.contains(&attr.attr(db).as_syntax_node().get_text_without_trivia(db)) { - plugin_diagnostics.push(( - module_file_id, - PluginDiagnostic::error(&attr, "Unsupported attribute.".to_string()), - )); + plugin_diagnostics + .push(PluginDiagnostic::error(&attr, "Unsupported attribute.".to_string())); } } } @@ -641,12 +669,11 @@ pub fn validate_attributes_flat( fn validate_attributes_element_list( db: &dyn SyntaxGroup, allowed_attributes: &OrderedHashSet, - module_file_id: ModuleFileId, items: &ElementList, - plugin_diagnostics: &mut Vec<(ModuleFileId, PluginDiagnostic)>, + plugin_diagnostics: &mut Vec, ) { for item in items.elements(db) { - validate_attributes_flat(db, allowed_attributes, module_file_id, &item, plugin_diagnostics); + validate_attributes_flat(db, allowed_attributes, &item, plugin_diagnostics); } } @@ -655,18 +682,16 @@ fn validate_attributes_element_list, - module_file_id: ModuleFileId, item_ast: &ast::ModuleItem, - plugin_diagnostics: &mut Vec<(ModuleFileId, PluginDiagnostic)>, + plugin_diagnostics: &mut Vec, ) { - validate_attributes_flat(db, allowed_attributes, module_file_id, item_ast, plugin_diagnostics); + validate_attributes_flat(db, allowed_attributes, item_ast, plugin_diagnostics); match item_ast { ast::ModuleItem::Trait(item) => { if let ast::MaybeTraitBody::Some(body) = item.body(db) { validate_attributes_element_list( db, allowed_attributes, - module_file_id, &body.items(db), plugin_diagnostics, ); @@ -677,7 +702,6 @@ fn validate_attributes( validate_attributes_element_list( db, allowed_attributes, - module_file_id, &body.items(db), plugin_diagnostics, ); @@ -687,7 +711,6 @@ fn validate_attributes( validate_attributes_element_list( db, allowed_attributes, - module_file_id, &item.members(db), plugin_diagnostics, ); @@ -696,7 +719,6 @@ fn validate_attributes( validate_attributes_element_list( db, allowed_attributes, - module_file_id, &item.variants(db), plugin_diagnostics, ); @@ -971,11 +993,11 @@ pub fn module_ancestors(db: &dyn DefsGroup, module_id: ModuleId) -> OrderedHashS } /// Returns the generated_file_infos of the given module. -pub fn module_generated_file_infos( +pub fn module_generated_file_aux_data( db: &dyn DefsGroup, module_id: ModuleId, -) -> Maybe]>> { - Ok(db.priv_module_data(module_id)?.generated_file_infos.into()) +) -> Maybe]>> { + Ok(db.priv_module_data(module_id)?.generated_file_aux_data.into()) } /// Returns all the plugin diagnostics of the given module. diff --git a/crates/cairo-lang-semantic/src/expr/compute.rs b/crates/cairo-lang-semantic/src/expr/compute.rs index ee5ae3eaa90..ec2a86c2822 100644 --- a/crates/cairo-lang-semantic/src/expr/compute.rs +++ b/crates/cairo-lang-semantic/src/expr/compute.rs @@ -3354,17 +3354,10 @@ fn check_struct_member_is_visible( /// reported. fn validate_statement_attributes(ctx: &mut ComputationContext<'_>, syntax: &ast::Statement) { let allowed_attributes = ctx.db.allowed_statement_attributes(); - let module_file_id = ctx.resolver.module_file_id; let mut diagnostics = vec![]; - validate_attributes_flat( - ctx.db.upcast(), - &allowed_attributes, - module_file_id, - syntax, - &mut diagnostics, - ); + validate_attributes_flat(ctx.db.upcast(), &allowed_attributes, syntax, &mut diagnostics); // Translate the plugin diagnostics to semantic diagnostics. - for (_, diagnostic) in diagnostics { + for diagnostic in diagnostics { ctx.diagnostics .report(diagnostic.stable_ptr, SemanticDiagnosticKind::UnknownStatementAttribute); } diff --git a/crates/cairo-lang-starknet/src/abi.rs b/crates/cairo-lang-starknet/src/abi.rs index fe6f65d8699..8127b934108 100644 --- a/crates/cairo-lang-starknet/src/abi.rs +++ b/crates/cairo-lang-starknet/src/abi.rs @@ -837,8 +837,8 @@ fn fetch_event_data(db: &dyn SemanticGroup, event_type_id: TypeId) -> Option()?.event_data.clone()) } diff --git a/crates/cairo-lang-starknet/src/contract.rs b/crates/cairo-lang-starknet/src/contract.rs index 6d91f373517..1c9827c66bf 100644 --- a/crates/cairo-lang-starknet/src/contract.rs +++ b/crates/cairo-lang-starknet/src/contract.rs @@ -54,14 +54,14 @@ impl ContractDeclaration { /// Returns the contract declaration of a given module if it is a contract module. pub fn module_contract(db: &dyn SemanticGroup, module_id: ModuleId) -> Option { - let generated_file_infos = db.module_generated_file_infos(module_id).ok()?; + let all_aux_data = db.module_generated_file_aux_data(module_id).ok()?; - // When a module is generated by a plugin the same generated_file_info appears in two + // When a module is generated by a plugin the same aux data appears in two // places: - // 1. db.module_generated_file_infos(*original_module_id)?[k] (with k > 0). - // 2. db.module_generated_file_infos(*generated_module_id)?[0]. + // 1. db.module_generated_file_aux_data(*original_module_id)?[k] (with k > 0). + // 2. db.module_generated_file_aux_data(*generated_module_id)?[0]. // We are interested in modules that the plugin acted on and not modules that were - // created by the plugin, so we skip generated_file_infos[0]. + // created by the plugin, so we skip all_aux_data[0]. // For example if we have // mod a { // #[starknet::contract] @@ -69,9 +69,9 @@ pub fn module_contract(db: &dyn SemanticGroup, module_id: ModuleId) -> Option