From eb2d31894cc8be1f2e86c1dcce0cb26c3d70dd63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sm=C3=B3=C5=82ka?= Date: Mon, 9 Dec 2024 22:16:28 +0100 Subject: [PATCH] Introduced per-crate plugin queries to the compiler commit-id:f0989263 --- crates/cairo-lang-defs/src/db.rs | 47 ++++++++------ crates/cairo-lang-defs/src/test.rs | 12 ++-- crates/cairo-lang-doc/src/tests/test_utils.rs | 5 +- crates/cairo-lang-lowering/src/test_utils.rs | 8 +-- crates/cairo-lang-plugins/src/test.rs | 22 +++++-- crates/cairo-lang-semantic/src/db.rs | 20 +++--- .../src/diagnostic_test.rs | 11 +++- .../cairo-lang-semantic/src/expr/compute.rs | 16 +++-- crates/cairo-lang-semantic/src/items/enm.rs | 12 +++- .../src/items/feature_kind.rs | 9 ++- .../src/items/structure.rs | 12 +++- crates/cairo-lang-semantic/src/test_utils.rs | 7 +- crates/cairo-lang-semantic/src/types.rs | 50 ++++++++++++++- .../src/executables.rs | 64 ++++++++++--------- .../src/test_utils.rs | 7 +- 15 files changed, 193 insertions(+), 109 deletions(-) diff --git a/crates/cairo-lang-defs/src/db.rs b/crates/cairo-lang-defs/src/db.rs index 876909b8986..f5ddcbfd453 100644 --- a/crates/cairo-lang-defs/src/db.rs +++ b/crates/cairo-lang-defs/src/db.rs @@ -23,10 +23,7 @@ use itertools::{Itertools, chain}; use salsa::InternKey; use crate::ids::*; -use crate::plugin::{ - DynGeneratedFileAuxData, InlineMacroExprPlugin, MacroPlugin, MacroPluginMetadata, - PluginDiagnostic, -}; +use crate::plugin::{DynGeneratedFileAuxData, MacroPlugin, MacroPluginMetadata, PluginDiagnostic}; /// Salsa database interface. /// See [`super::ids`] for further details. @@ -95,10 +92,6 @@ pub trait DefsGroup: // Plugins. // ======== - #[salsa::input] - fn macro_plugins(&self) -> Vec>; // TODO: Delete in favour or [`default_macro_plugins`] - #[salsa::input] // TODO: Delete in favour or [`default_inline_macro_plugins`] - fn inline_macro_plugins(&self) -> Arc>>; #[salsa::input] fn default_macro_plugins(&self) -> Vec; @@ -141,7 +134,7 @@ pub trait DefsGroup: /// Returns the set of attributes allowed anywhere. /// An attribute on any item that is not in this set will be handled as an unknown attribute. - fn allowed_attributes(&self) -> Arc>; + fn allowed_attributes(&self, crate_id: CrateId) -> Arc>; /// Returns the set of attributes allowed on statements. /// An attribute on a statement that is not in this set will be handled as an unknown attribute. @@ -149,11 +142,11 @@ pub trait DefsGroup: /// Returns the set of `derive` that were declared as by a plugin. /// A derive that is not in this set will be handled as an unknown derive. - fn declared_derives(&self) -> Arc>; + fn declared_derives(&self, crate_id: CrateId) -> Arc>; /// Returns the set of attributes that were declared as phantom type attributes by a plugin, /// i.e. a type marked with this attribute is considered a phantom type. - fn declared_phantom_type_attributes(&self) -> Arc>; + fn declared_phantom_type_attributes(&self, crate_id: CrateId) -> Arc>; /// Checks whether the submodule is defined as inline. fn is_submodule_inline(&self, submodule_id: SubmoduleId) -> Maybe; @@ -321,7 +314,7 @@ fn crate_inline_macro_plugins( db.default_inline_macro_plugins() } -fn allowed_attributes(db: &dyn DefsGroup) -> Arc> { +fn allowed_attributes(db: &dyn DefsGroup, crate_id: CrateId) -> Arc> { let base_attrs = [ INLINE_ATTR, MUST_USE_ATTR, @@ -338,7 +331,9 @@ fn allowed_attributes(db: &dyn DefsGroup) -> Arc> { ]; Arc::new(OrderedHashSet::from_iter(chain!( base_attrs.map(|attr| attr.into()), - db.macro_plugins().into_iter().flat_map(|plugin| plugin.declared_attributes()) + db.crate_macro_plugins(crate_id) + .into_iter() + .flat_map(|plugin| db.lookup_intern_macro_plugin(plugin).declared_attributes()) ))) } @@ -347,16 +342,23 @@ fn allowed_statement_attributes(_db: &dyn DefsGroup) -> Arc Arc> { +fn declared_derives(db: &dyn DefsGroup, crate_id: CrateId) -> Arc> { Arc::new(OrderedHashSet::from_iter( - db.macro_plugins().into_iter().flat_map(|plugin| plugin.declared_derives()), + db.crate_macro_plugins(crate_id) + .into_iter() + .flat_map(|plugin| db.lookup_intern_macro_plugin(plugin).declared_derives()), )) } -fn declared_phantom_type_attributes(db: &dyn DefsGroup) -> Arc> { +fn declared_phantom_type_attributes( + db: &dyn DefsGroup, + crate_id: CrateId, +) -> Arc> { Arc::new(OrderedHashSet::from_iter(chain!( [PHANTOM_ATTR.into()], - db.macro_plugins().into_iter().flat_map(|plugin| plugin.phantom_type_attributes()) + db.crate_macro_plugins(crate_id) + .into_iter() + .flat_map(|plugin| db.lookup_intern_macro_plugin(plugin).phantom_type_attributes()) ))) } @@ -706,11 +708,12 @@ fn priv_module_sub_files( } .unwrap_or_else(|| file_syntax.items(syntax_db)); - let allowed_attributes = db.allowed_attributes(); + let crate_id = module_id.owning_crate(db); + + let allowed_attributes = db.allowed_attributes(crate_id); // 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)) @@ -721,7 +724,7 @@ fn priv_module_sub_files( .unwrap_or_default(); let metadata = MacroPluginMetadata { cfg_set: &cfg_set, - declared_derives: &db.declared_derives(), + declared_derives: &db.declared_derives(crate_id), allowed_features: &allowed_features, edition, }; @@ -736,7 +739,9 @@ fn priv_module_sub_files( // 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() { + for plugin_id in db.crate_macro_plugins(crate_id) { + let plugin = db.lookup_intern_macro_plugin(plugin_id); + let result = plugin.generate_code(db.upcast(), item_ast.clone(), &metadata); plugin_diagnostics.extend(result.diagnostics); if result.remove_original_item { diff --git a/crates/cairo-lang-defs/src/test.rs b/crates/cairo-lang-defs/src/test.rs index dd04906ee25..81a05d43d0f 100644 --- a/crates/cairo-lang-defs/src/test.rs +++ b/crates/cairo-lang-defs/src/test.rs @@ -19,8 +19,8 @@ use indoc::indoc; use crate::db::{DefsDatabase, DefsGroup, try_ext_as_virtual_impl}; use crate::ids::{ - FileIndex, GenericParamLongId, ModuleFileId, ModuleId, ModuleItemId, NamedLanguageElementId, - SubmoduleLongId, + FileIndex, GenericParamLongId, MacroPluginLongId, ModuleFileId, ModuleId, ModuleItemId, + NamedLanguageElementId, SubmoduleLongId, }; use crate::plugin::{ MacroPlugin, MacroPluginMetadata, PluginDiagnostic, PluginGeneratedFile, PluginResult, @@ -40,10 +40,10 @@ impl Default for DatabaseForTesting { fn default() -> Self { let mut res = Self { storage: Default::default() }; init_files_group(&mut res); - res.set_macro_plugins(vec![ - Arc::new(FooToBarPlugin), - Arc::new(RemoveOrigPlugin), - Arc::new(DummyPlugin), + res.set_default_macro_plugins(vec![ + res.intern_macro_plugin(MacroPluginLongId(Arc::new(FooToBarPlugin))), + res.intern_macro_plugin(MacroPluginLongId(Arc::new(RemoveOrigPlugin))), + res.intern_macro_plugin(MacroPluginLongId(Arc::new(DummyPlugin))), ]); res } diff --git a/crates/cairo-lang-doc/src/tests/test_utils.rs b/crates/cairo-lang-doc/src/tests/test_utils.rs index ba6353ecc04..e8980d286db 100644 --- a/crates/cairo-lang-doc/src/tests/test_utils.rs +++ b/crates/cairo-lang-doc/src/tests/test_utils.rs @@ -8,7 +8,8 @@ use cairo_lang_filesystem::db::{ use cairo_lang_filesystem::detect::detect_corelib; use cairo_lang_filesystem::ids::{CrateId, Directory, FileLongId}; use cairo_lang_parser::db::{ParserDatabase, ParserGroup}; -use cairo_lang_semantic::db::{SemanticDatabase, SemanticGroup}; +use cairo_lang_semantic::db::{PluginSuiteInput, SemanticDatabase, SemanticGroup}; +use cairo_lang_semantic::plugin::PluginSuite; use cairo_lang_syntax::node::db::{SyntaxDatabase, SyntaxGroup}; use cairo_lang_utils::{Intern, Upcast}; @@ -33,7 +34,7 @@ impl Default for TestDatabase { fn default() -> Self { let mut res = Self { storage: Default::default() }; init_files_group(&mut res); - res.set_macro_plugins(vec![]); + res.set_default_plugins_from_suite(PluginSuite::default()); res } } diff --git a/crates/cairo-lang-lowering/src/test_utils.rs b/crates/cairo-lang-lowering/src/test_utils.rs index c039d6f4cba..30aa34483a1 100644 --- a/crates/cairo-lang-lowering/src/test_utils.rs +++ b/crates/cairo-lang-lowering/src/test_utils.rs @@ -7,7 +7,7 @@ use cairo_lang_filesystem::db::{ use cairo_lang_filesystem::detect::detect_corelib; use cairo_lang_filesystem::ids::VirtualFile; use cairo_lang_parser::db::{ParserDatabase, ParserGroup}; -use cairo_lang_semantic::db::{SemanticDatabase, SemanticGroup}; +use cairo_lang_semantic::db::{PluginSuiteInput, SemanticDatabase, SemanticGroup}; use cairo_lang_semantic::inline_macros::get_default_plugin_suite; use cairo_lang_syntax::node::db::{SyntaxDatabase, SyntaxGroup}; use cairo_lang_utils::Upcast; @@ -41,11 +41,7 @@ impl LoweringDatabaseForTesting { pub fn new() -> Self { let mut res = LoweringDatabaseForTesting { storage: Default::default() }; init_files_group(&mut res); - let suite = get_default_plugin_suite(); - res.set_macro_plugins(suite.plugins); - res.set_inline_macro_plugins(suite.inline_macro_plugins.into()); - res.set_analyzer_plugins(suite.analyzer_plugins); - + res.set_default_plugins_from_suite(get_default_plugin_suite()); let corelib_path = detect_corelib().expect("Corelib not found in default location."); init_dev_corelib(&mut res, corelib_path); init_lowering_group(&mut res, InliningStrategy::Default); diff --git a/crates/cairo-lang-plugins/src/test.rs b/crates/cairo-lang-plugins/src/test.rs index 588c81f756b..201e6a609b9 100644 --- a/crates/cairo-lang-plugins/src/test.rs +++ b/crates/cairo-lang-plugins/src/test.rs @@ -2,7 +2,7 @@ use std::default::Default; use std::sync::Arc; use cairo_lang_defs::db::{DefsDatabase, DefsGroup, try_ext_as_virtual_impl}; -use cairo_lang_defs::ids::ModuleId; +use cairo_lang_defs::ids::{MacroPluginLongId, ModuleId}; use cairo_lang_defs::plugin::{ MacroPlugin, MacroPluginMetadata, PluginDiagnostic, PluginGeneratedFile, PluginResult, }; @@ -64,7 +64,12 @@ impl Default for DatabaseForTesting { fn default() -> Self { let mut res = Self { storage: Default::default() }; init_files_group(&mut res); - res.set_macro_plugins(get_base_plugins()); + res.set_default_macro_plugins( + get_base_plugins() + .into_iter() + .map(|plugin| res.intern_macro_plugin(MacroPluginLongId(plugin))) + .collect(), + ); res } } @@ -112,9 +117,16 @@ pub fn test_expand_plugin_inner( extra_plugins: &[Arc], ) -> TestRunnerResult { let db = &mut DatabaseForTesting::default(); - let mut plugins = db.macro_plugins(); - plugins.extend_from_slice(extra_plugins); - db.set_macro_plugins(plugins); + + let extra_plugins = extra_plugins + .iter() + .cloned() + .map(|plugin| db.intern_macro_plugin(MacroPluginLongId(plugin))); + + let mut plugins = db.default_macro_plugins(); + plugins.extend(extra_plugins); + + db.set_default_macro_plugins(plugins.clone()); let cfg_set: Option = inputs.get("cfg").map(|s| serde_json::from_str(s.as_str()).unwrap()); diff --git a/crates/cairo-lang-semantic/src/db.rs b/crates/cairo-lang-semantic/src/db.rs index 0043d6e5b2a..cead40416d3 100644 --- a/crates/cairo-lang-semantic/src/db.rs +++ b/crates/cairo-lang-semantic/src/db.rs @@ -1557,8 +1557,6 @@ pub trait SemanticGroup: // Analyzer plugins. // ======== - #[salsa::input] - fn analyzer_plugins(&self) -> Vec>; #[salsa::input] fn default_analyzer_plugins(&self) -> Vec; @@ -1577,7 +1575,7 @@ pub trait SemanticGroup: /// Returns the set of `allow` that were declared as by a plugin. /// An allow that is not in this set will be handled as an unknown allow. - fn declared_allows(&self) -> Arc>; + fn declared_allows(&self, crate_id: CrateId) -> Arc>; // Helpers for language server. // ============================ @@ -1712,7 +1710,10 @@ fn module_semantic_diagnostics( diagnostics.extend(db.global_use_semantic_diagnostics(*global_use)); } add_unused_item_diagnostics(db, module_id, &data, &mut diagnostics); - for analyzer_plugin in db.analyzer_plugins().iter() { + for analyzer_plugin_id in db.crate_analyzer_plugins(module_id.owning_crate(db.upcast())).iter() + { + let analyzer_plugin = db.lookup_intern_analyzer_plugin(*analyzer_plugin_id); + for diag in analyzer_plugin.diagnostics(db, module_id) { diagnostics.add(SemanticDiagnostic::new( StableLocation::new(diag.stable_ptr), @@ -1729,9 +1730,11 @@ fn crate_analyzer_plugins(db: &dyn SemanticGroup, _crate_id: CrateId) -> Vec Arc> { +fn declared_allows(db: &dyn SemanticGroup, crate_id: CrateId) -> Arc> { Arc::new(OrderedHashSet::from_iter( - db.analyzer_plugins().into_iter().flat_map(|plugin| plugin.declared_allows()), + db.crate_analyzer_plugins(crate_id) + .into_iter() + .flat_map(|plugin| db.lookup_intern_analyzer_plugin(plugin).declared_allows()), )) } @@ -1885,11 +1888,6 @@ pub trait PluginSuiteInput: SemanticGroup { fn set_default_plugins_from_suite(&mut self, suite: PluginSuite) { let PluginSuite { plugins, inline_macro_plugins, analyzer_plugins } = suite; - // NOTE: kept for compatibility and testing, removed later in the stack. - self.set_macro_plugins(plugins.clone()); - self.set_inline_macro_plugins(Arc::new(inline_macro_plugins.clone())); - self.set_analyzer_plugins(analyzer_plugins.clone()); - let macro_plugins = plugins .into_iter() .map(|plugin| self.intern_macro_plugin(MacroPluginLongId(plugin))) diff --git a/crates/cairo-lang-semantic/src/diagnostic_test.rs b/crates/cairo-lang-semantic/src/diagnostic_test.rs index 3a4dbcdee72..0ce56ce557e 100644 --- a/crates/cairo-lang-semantic/src/diagnostic_test.rs +++ b/crates/cairo-lang-semantic/src/diagnostic_test.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use cairo_lang_defs::db::DefsGroup; -use cairo_lang_defs::ids::{GenericTypeId, ModuleId, TopLevelLanguageElementId}; +use cairo_lang_defs::ids::{GenericTypeId, MacroPluginLongId, ModuleId, TopLevelLanguageElementId}; use cairo_lang_defs::patcher::{PatchBuilder, RewriteNode}; use cairo_lang_defs::plugin::{ MacroPlugin, MacroPluginMetadata, PluginDiagnostic, PluginGeneratedFile, PluginResult, @@ -14,6 +14,7 @@ use pretty_assertions::assert_eq; use test_log::test; use crate::db::SemanticGroup; +use crate::ids::AnalyzerPluginLongId; use crate::items::us::SemanticUseEx; use crate::plugin::AnalyzerPlugin; use crate::resolve::ResolvedGenericItem; @@ -139,7 +140,9 @@ impl MacroPlugin for AddInlineModuleDummyPlugin { fn test_inline_module_diagnostics() { let mut db_val = SemanticDatabaseForTesting::new_empty(); let db = &mut db_val; - db.set_macro_plugins(vec![Arc::new(AddInlineModuleDummyPlugin)]); + db.set_default_macro_plugins(vec![ + db.intern_macro_plugin(MacroPluginLongId(Arc::new(AddInlineModuleDummyPlugin))), + ]); let crate_id = setup_test_crate(db, indoc! {" mod a { #[test_change_return_type] @@ -239,7 +242,9 @@ impl AnalyzerPlugin for NoU128RenameAnalyzerPlugin { fn test_analyzer_diagnostics() { let mut db_val = SemanticDatabaseForTesting::new_empty(); let db = &mut db_val; - db.set_analyzer_plugins(vec![Arc::new(NoU128RenameAnalyzerPlugin)]); + db.set_default_analyzer_plugins(vec![ + db.intern_analyzer_plugin(AnalyzerPluginLongId(Arc::new(NoU128RenameAnalyzerPlugin))), + ]); let crate_id = setup_test_crate(db, indoc! {" mod inner { use core::integer::u128 as long_u128_rename; diff --git a/crates/cairo-lang-semantic/src/expr/compute.rs b/crates/cairo-lang-semantic/src/expr/compute.rs index a75b27847c0..c93932a379d 100644 --- a/crates/cairo-lang-semantic/src/expr/compute.rs +++ b/crates/cairo-lang-semantic/src/expr/compute.rs @@ -15,7 +15,7 @@ use cairo_lang_defs::ids::{ MemberId, ModuleItemId, NamedLanguageElementId, StatementConstLongId, StatementItemId, StatementUseLongId, TraitFunctionId, TraitId, VarId, }; -use cairo_lang_defs::plugin::MacroPluginMetadata; +use cairo_lang_defs::plugin::{InlineMacroExprPlugin, MacroPluginMetadata}; use cairo_lang_diagnostics::{Maybe, ToOption, skip_diagnostic}; use cairo_lang_filesystem::cfg::CfgSet; use cairo_lang_filesystem::ids::{FileKind, FileLongId, VirtualFile}; @@ -433,10 +433,15 @@ fn compute_expr_inline_macro_semantic( ) -> Maybe { let syntax_db = ctx.db.upcast(); + let crate_id = ctx.resolver.owning_crate_id; + let macro_name = syntax.path(syntax_db).as_syntax_node().get_text_without_trivia(syntax_db); - let Some(macro_plugin) = ctx.db.inline_macro_plugins().get(¯o_name).cloned() else { + let Some(macro_plugin_id) = + ctx.db.crate_inline_macro_plugins(crate_id).get(¯o_name).cloned() + else { return Err(ctx.diagnostics.report(syntax, InlineMacroNotFound(macro_name.into()))); }; + let macro_plugin = ctx.db.lookup_intern_inline_macro_plugin(macro_plugin_id); // Skipping expanding an inline macro if it had a parser error. if syntax.as_syntax_node().descendants(syntax_db).any(|node| { @@ -457,7 +462,7 @@ fn compute_expr_inline_macro_semantic( let result = macro_plugin.generate_code(syntax_db, syntax, &MacroPluginMetadata { cfg_set: &ctx.cfg_set, - declared_derives: &ctx.db.declared_derives(), + declared_derives: &ctx.db.declared_derives(crate_id), allowed_features: &ctx.resolver.data.feature_config.allowed_features, edition: ctx.resolver.settings.edition, }); @@ -3393,6 +3398,9 @@ pub fn compute_statement_semantic( ) -> Maybe { let db = ctx.db; let syntax_db = db.upcast(); + + let crate_id = ctx.resolver.owning_crate_id; + // As for now, statement attributes does not have any semantic affect, so we only validate they // are allowed. validate_statement_attributes(ctx, &syntax); @@ -3400,7 +3408,7 @@ pub fn compute_statement_semantic( .resolver .data .feature_config - .override_with(extract_item_feature_config(db, &syntax, ctx.diagnostics)); + .override_with(extract_item_feature_config(db, crate_id, &syntax, ctx.diagnostics)); let statement = match &syntax { ast::Statement::Let(let_syntax) => { let rhs_syntax = &let_syntax.rhs(syntax_db); diff --git a/crates/cairo-lang-semantic/src/items/enm.rs b/crates/cairo-lang-semantic/src/items/enm.rs index c87d4000924..5a7b3d3fa20 100644 --- a/crates/cairo-lang-semantic/src/items/enm.rs +++ b/crates/cairo-lang-semantic/src/items/enm.rs @@ -188,7 +188,10 @@ pub fn priv_enum_definition_data( db: &dyn SemanticGroup, enum_id: EnumId, ) -> Maybe { - let module_file_id = enum_id.module_file_id(db.upcast()); + let defs_db = db.upcast(); + + let module_file_id = enum_id.module_file_id(defs_db); + let crate_id = module_file_id.0.owning_crate(defs_db); let mut diagnostics = SemanticDiagnostics::default(); // TODO(spapini): when code changes in a file, all the AST items change (as they contain a path // to the green root that changes. Once ASTs are rooted on items, use a selector that picks only @@ -213,7 +216,7 @@ pub fn priv_enum_definition_data( let feature_restore = resolver .data .feature_config - .override_with(extract_item_feature_config(db, &variant, &mut diagnostics)); + .override_with(extract_item_feature_config(db, crate_id, &variant, &mut diagnostics)); let id = VariantLongId(module_file_id, variant.stable_ptr()).intern(db); let ty = match variant.type_clause(syntax_db) { ast::OptionTypeClause::Empty(_) => unit_ty(db), @@ -254,10 +257,13 @@ pub fn enum_definition_diagnostics( let Ok(data) = db.priv_enum_definition_data(enum_id) else { return Default::default(); }; + + let crate_id = data.resolver_data.module_file_id.0.owning_crate(db.upcast()); + // If the enum is a phantom type, no need to check if its variants are fully valid types, as // they won't be used. if db - .declared_phantom_type_attributes() + .declared_phantom_type_attributes(crate_id) .iter() .any(|attr| enum_id.has_attr(db, attr).unwrap_or_default()) { diff --git a/crates/cairo-lang-semantic/src/items/feature_kind.rs b/crates/cairo-lang-semantic/src/items/feature_kind.rs index 1ee2dd5e10e..b024b9359d8 100644 --- a/crates/cairo-lang-semantic/src/items/feature_kind.rs +++ b/crates/cairo-lang-semantic/src/items/feature_kind.rs @@ -1,6 +1,7 @@ use cairo_lang_defs::diagnostic_utils::StableLocation; use cairo_lang_defs::ids::{LanguageElementId, ModuleId}; use cairo_lang_diagnostics::DiagnosticsBuilder; +use cairo_lang_filesystem::ids::CrateId; use cairo_lang_syntax::attribute::consts::{ ALLOW_ATTR, DEPRECATED_ATTR, FEATURE_ATTR, INTERNAL_ATTR, UNSTABLE_ATTR, }; @@ -177,6 +178,7 @@ pub struct FeatureConfigRestore { /// Returns the allowed features of an object which supports attributes. pub fn extract_item_feature_config( db: &dyn SemanticGroup, + crate_id: CrateId, syntax: &impl QueryAttrs, diagnostics: &mut SemanticDiagnostics, ) -> FeatureConfig { @@ -212,7 +214,7 @@ pub fn extract_item_feature_config( config.allow_unused_imports = true; true } - other => db.declared_allows().contains(other), + other => db.declared_allows(crate_id).contains(other), }, ); config @@ -253,7 +255,8 @@ pub fn extract_feature_config( ) -> FeatureConfig { let defs_db = db.upcast(); let mut current_module_id = element_id.parent_module(defs_db); - let mut config_stack = vec![extract_item_feature_config(db, syntax, diagnostics)]; + let crate_id = current_module_id.owning_crate(defs_db); + let mut config_stack = vec![extract_item_feature_config(db, crate_id, syntax, diagnostics)]; let mut config = loop { match current_module_id { ModuleId::CrateRoot(crate_id) => { @@ -270,7 +273,7 @@ pub fn extract_feature_config( let module = &db.module_submodules(current_module_id).unwrap()[&id]; // TODO(orizi): Add parent module diagnostics. let ignored = &mut SemanticDiagnostics::default(); - config_stack.push(extract_item_feature_config(db, module, ignored)); + config_stack.push(extract_item_feature_config(db, crate_id, module, ignored)); } } }; diff --git a/crates/cairo-lang-semantic/src/items/structure.rs b/crates/cairo-lang-semantic/src/items/structure.rs index a986656d8ee..1df0c19179a 100644 --- a/crates/cairo-lang-semantic/src/items/structure.rs +++ b/crates/cairo-lang-semantic/src/items/structure.rs @@ -165,7 +165,10 @@ pub fn priv_struct_definition_data( db: &dyn SemanticGroup, struct_id: StructId, ) -> Maybe { - let module_file_id = struct_id.module_file_id(db.upcast()); + let defs_db = db.upcast(); + + let module_file_id = struct_id.module_file_id(defs_db); + let crate_id = module_file_id.0.owning_crate(defs_db); let mut diagnostics = SemanticDiagnostics::default(); // TODO(spapini): when code changes in a file, all the AST items change (as they contain a path // to the green root that changes. Once ASTs are rooted on items, use a selector that picks only @@ -191,7 +194,7 @@ pub fn priv_struct_definition_data( let feature_restore = resolver .data .feature_config - .override_with(extract_item_feature_config(db, &member, &mut diagnostics)); + .override_with(extract_item_feature_config(db, crate_id, &member, &mut diagnostics)); let id = MemberLongId(module_file_id, member.stable_ptr()).intern(db); let ty = resolve_type( db, @@ -234,10 +237,13 @@ pub fn struct_definition_diagnostics( let Ok(data) = db.priv_struct_definition_data(struct_id) else { return Default::default(); }; + + let crate_id = data.resolver_data.module_file_id.0.owning_crate(db.upcast()); + // If the struct is a phantom type, no need to check if its members are fully valid types, as // they won't be used. if db - .declared_phantom_type_attributes() + .declared_phantom_type_attributes(crate_id) .iter() .any(|attr| struct_id.has_attr(db, attr).unwrap_or_default()) { diff --git a/crates/cairo-lang-semantic/src/test_utils.rs b/crates/cairo-lang-semantic/src/test_utils.rs index 69097e35dab..b390b30b4bd 100644 --- a/crates/cairo-lang-semantic/src/test_utils.rs +++ b/crates/cairo-lang-semantic/src/test_utils.rs @@ -17,7 +17,7 @@ use cairo_lang_test_utils::verify_diagnostics_expectation; use cairo_lang_utils::ordered_hash_map::OrderedHashMap; use cairo_lang_utils::{Intern, LookupIntern, OptionFrom, Upcast, extract_matches}; -use crate::db::{SemanticDatabase, SemanticGroup}; +use crate::db::{PluginSuiteInput, SemanticDatabase, SemanticGroup}; use crate::inline_macros::get_default_plugin_suite; use crate::items::functions::GenericFunctionId; use crate::{ConcreteFunctionWithBodyId, SemanticDiagnostic, semantic}; @@ -41,10 +41,7 @@ impl SemanticDatabaseForTesting { pub fn new_empty() -> Self { let mut res = SemanticDatabaseForTesting { storage: Default::default() }; init_files_group(&mut res); - let suite = get_default_plugin_suite(); - res.set_macro_plugins(suite.plugins); - res.set_inline_macro_plugins(suite.inline_macro_plugins.into()); - res.set_analyzer_plugins(suite.analyzer_plugins); + res.set_default_plugins_from_suite(get_default_plugin_suite()); let corelib_path = detect_corelib().expect("Corelib not found in default location."); init_dev_corelib(&mut res, corelib_path); res diff --git a/crates/cairo-lang-semantic/src/types.rs b/crates/cairo-lang-semantic/src/types.rs index 96ff17ad174..6d0692a516e 100644 --- a/crates/cairo-lang-semantic/src/types.rs +++ b/crates/cairo-lang-semantic/src/types.rs @@ -1,8 +1,8 @@ use cairo_lang_debug::DebugWithDb; use cairo_lang_defs::diagnostic_utils::StableLocation; use cairo_lang_defs::ids::{ - EnumId, ExternTypeId, GenericParamId, GenericTypeId, ModuleFileId, NamedLanguageElementId, - StructId, TraitTypeId, + EnumId, ExternTypeId, GenericParamId, GenericTypeId, LanguageElementId, ModuleFileId, + NamedLanguageElementId, StructId, TraitTypeId, }; use cairo_lang_diagnostics::{DiagnosticAdded, Maybe}; use cairo_lang_proc_macros::SemanticObject; @@ -105,6 +105,12 @@ impl TypeId { db.priv_type_is_var_free(*self) } + /// Returns a [`ModuleFileId`] if the type represented by [`TypeId`] + /// is associated with some. + pub fn module_file_id(self, db: &dyn SemanticGroup) -> Option { + db.lookup_intern_type(self).module_file_id(db) + } + /// Returns whether the type is phantom. /// Type is considered phantom if it has the `#[phantom]` attribute, or is a tuple or fixed /// sized array containing it. @@ -141,12 +147,50 @@ impl TypeLongId { }) } + /// Returns a [`ModuleFileId`] if the type represented by [`TypeLongId`] + /// is associated with some. + pub fn module_file_id(&self, db: &dyn SemanticGroup) -> Option { + let defs_db = db.upcast(); + + match self { + TypeLongId::Concrete(id) => match id { + ConcreteTypeId::Struct(id) => { + Some(db.lookup_intern_concrete_struct(*id).struct_id.module_file_id(defs_db)) + } + ConcreteTypeId::Enum(id) => { + Some(db.lookup_intern_concrete_enum(*id).enum_id.module_file_id(defs_db)) + } + ConcreteTypeId::Extern(id) => Some( + db.lookup_intern_concrete_extern_type(*id) + .extern_type_id + .module_file_id(defs_db), + ), + }, + TypeLongId::Snapshot(type_id) => type_id.module_file_id(db), + TypeLongId::GenericParameter(id) => Some(id.module_file_id(defs_db)), + TypeLongId::FixedSizeArray { type_id, .. } => type_id.module_file_id(db), + TypeLongId::TraitType(id) => Some(id.module_file_id(defs_db)), + TypeLongId::ImplType(id) => Some(db.lookup_intern_concrete_trait(id.impl_id.concrete_trait(db).ok()?).trait_id.module_file_id(defs_db)), + TypeLongId::Tuple(_) // Types of the tuple can originate from different modules. + | TypeLongId::Var(_) + | TypeLongId::Coupon(_) + | TypeLongId::Closure(_) + | TypeLongId::Missing(_) => None, + } + } + /// Returns whether the type is phantom. /// Type is considered phantom if it has the `#[phantom]` attribute, (or an other attribute /// declared by a plugin as defining a phantom type), or is a tuple or fixed sized array /// containing it. pub fn is_phantom(&self, db: &dyn SemanticGroup) -> bool { - let phantom_type_attributes = db.declared_phantom_type_attributes(); + let Some(module_file_id) = self.module_file_id(db) else { + return false; + }; + let crate_id = module_file_id.0.owning_crate(db.upcast()); + + let phantom_type_attributes = db.declared_phantom_type_attributes(crate_id); + match self { TypeLongId::Concrete(id) => match id { ConcreteTypeId::Struct(id) => phantom_type_attributes diff --git a/crates/cairo-lang-sierra-generator/src/executables.rs b/crates/cairo-lang-sierra-generator/src/executables.rs index a38fd333565..cf1f1e8bb9c 100644 --- a/crates/cairo-lang-sierra-generator/src/executables.rs +++ b/crates/cairo-lang-sierra-generator/src/executables.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use cairo_lang_defs::plugin::MacroPlugin; use cairo_lang_diagnostics::ToOption; use cairo_lang_filesystem::ids::CrateId; use cairo_lang_lowering::ids::ConcreteFunctionWithBodyId; @@ -24,41 +25,46 @@ pub fn find_executable_function_ids( db: &dyn SierraGenGroup, main_crate_ids: Vec, ) -> HashMap> { - let executable_attributes = db - .macro_plugins() - .iter() - .flat_map(|plugin| plugin.executable_attributes()) - .map(SmolStr::new) - .collect::>(); let mut executable_function_ids = HashMap::new(); - if !executable_attributes.is_empty() { - for crate_id in main_crate_ids { - for module in db.crate_modules(crate_id).iter() { - if let Some(free_functions) = db.module_free_functions(*module).to_option() { - for (free_func_id, body) in free_functions.iter() { - let found_attrs = executable_attributes - .clone() - .iter() - .filter(|attr| body.has_attr(db.upcast(), attr.as_str())) - .cloned() - .collect::>(); - if found_attrs.is_empty() { - // No executable attributes found. - continue; - } - // Find function corresponding to the node by full path. - let function_id = ConcreteFunctionWithBodyId::from_no_generics_free( - db.upcast(), - *free_func_id, - ); - if let Some(function_id) = function_id { - executable_function_ids.insert(function_id, found_attrs); - } + + for crate_id in main_crate_ids { + let executable_attributes = db + .crate_macro_plugins(crate_id) + .into_iter() + .flat_map(|plugin| db.lookup_intern_macro_plugin(plugin).executable_attributes()) + .map(SmolStr::new) + .collect::>(); + + if executable_attributes.is_empty() { + continue; + } + + for module in db.crate_modules(crate_id).iter() { + if let Some(free_functions) = db.module_free_functions(*module).to_option() { + for (free_func_id, body) in free_functions.iter() { + let found_attrs = executable_attributes + .clone() + .iter() + .filter(|attr| body.has_attr(db.upcast(), attr.as_str())) + .cloned() + .collect::>(); + if found_attrs.is_empty() { + // No executable attributes found. + continue; + } + // Find function corresponding to the node by full path. + let function_id = ConcreteFunctionWithBodyId::from_no_generics_free( + db.upcast(), + *free_func_id, + ); + if let Some(function_id) = function_id { + executable_function_ids.insert(function_id, found_attrs); } } } } } + executable_function_ids } diff --git a/crates/cairo-lang-sierra-generator/src/test_utils.rs b/crates/cairo-lang-sierra-generator/src/test_utils.rs index b9b39be2181..84828a52c1d 100644 --- a/crates/cairo-lang-sierra-generator/src/test_utils.rs +++ b/crates/cairo-lang-sierra-generator/src/test_utils.rs @@ -11,7 +11,7 @@ use cairo_lang_filesystem::flag::Flag; use cairo_lang_filesystem::ids::{FlagId, VirtualFile}; use cairo_lang_lowering::db::{LoweringDatabase, LoweringGroup}; use cairo_lang_parser::db::{ParserDatabase, ParserGroup}; -use cairo_lang_semantic::db::{SemanticDatabase, SemanticGroup}; +use cairo_lang_semantic::db::{PluginSuiteInput, SemanticDatabase, SemanticGroup}; use cairo_lang_semantic::test_utils::setup_test_crate; use cairo_lang_sierra::ids::{ConcreteLibfuncId, GenericLibfuncId}; use cairo_lang_sierra::program; @@ -65,10 +65,7 @@ impl SierraGenDatabaseForTesting { pub fn new_empty() -> Self { let mut res = SierraGenDatabaseForTesting { storage: Default::default() }; init_files_group(&mut res); - let suite = get_default_plugin_suite(); - res.set_macro_plugins(suite.plugins); - res.set_inline_macro_plugins(suite.inline_macro_plugins.into()); - res.set_analyzer_plugins(suite.analyzer_plugins); + res.set_default_plugins_from_suite(get_default_plugin_suite()); res.set_optimization_config(Arc::new( OptimizationConfig::default().with_minimal_movable_functions(),