From b8ddb6c765bcba785618bcad2db04bd286c25a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sm=C3=B3=C5=82ka?= Date: Wed, 18 Dec 2024 12:43:33 +0100 Subject: [PATCH] Introduced the new per-crate plugin logic --- Cargo.lock | 3 + Cargo.toml | 29 ++++++-- extensions/scarb-doc/src/db.rs | 17 +++-- scarb/src/compiler/compilers/lib.rs | 18 +++-- scarb/src/compiler/db.rs | 15 +++-- scarb/src/ops/compile.rs | 2 +- .../methods/defined_macros.rs | 67 ++++++++++++------- scarb/tests/proc_macro_server.rs | 14 ++-- .../scarb-proc-macro-server-types/Cargo.toml | 3 + .../src/methods/defined_macros.rs | 10 ++- 10 files changed, 125 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 739715731..1c373ee12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5157,8 +5157,11 @@ name = "scarb-proc-macro-server-types" version = "0.1.0" dependencies = [ "cairo-lang-macro 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-lang-semantic", + "cairo-lang-utils", "serde", "serde_json", + "smol_str", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ad8d80aae..0edc202c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,10 @@ expect-test = "1.5" flate2 = { version = "1.0.35", default-features = false, features = ["zlib"] } fs4 = { version = "0.7", features = ["tokio"] } fs_extra = "1" -futures = { version = "0.3", default-features = false, features = ["std", "async-await"] } +futures = { version = "0.3", default-features = false, features = [ + "std", + "async-await", +] } gix = ">=0.55" gix-path = "0.10" glob = "0.3" @@ -109,7 +112,14 @@ proc-macro2 = "1" quote = "1" ra_ap_toolchain = "0.0.218" redb = "2.3.0" -reqwest = { version = "0.11", features = ["gzip", "brotli", "deflate", "json", "stream", "multipart"], default-features = false } +reqwest = { version = "0.11", features = [ + "gzip", + "brotli", + "deflate", + "json", + "stream", + "multipart", +], default-features = false } salsa = { package = "rust-analyzer-salsa", version = "0.17.0-pre.6" } semver = { version = "1", features = ["serde"] } serde = { version = "1", features = ["serde_derive"] } @@ -130,7 +140,14 @@ tempfile = "3" test-case = "3" thiserror = "2" time = "0.3" -tokio = { version = "1", features = ["macros", "io-util", "process", "rt", "rt-multi-thread", "sync"] } +tokio = { version = "1", features = [ + "macros", + "io-util", + "process", + "rt", + "rt-multi-thread", + "sync", +] } toml = "0.8" toml_edit = { version = "0.22", features = ["serde"] } tower-http = { version = "0.4", features = ["fs"] } @@ -141,7 +158,11 @@ typed-builder = ">=0.17" url = { version = "2", features = ["serde"] } walkdir = "2" which = "7" -windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System", "Win32_System_Console"] } +windows-sys = { version = "0.59", features = [ + "Win32_Foundation", + "Win32_System", + "Win32_System_Console", +] } xshell = "0.2" xxhash-rust = { version = "0.8", features = ["xxh3"] } zip = { version = "0.6", default-features = false, features = ["deflate"] } diff --git a/extensions/scarb-doc/src/db.rs b/extensions/scarb-doc/src/db.rs index 468951bfb..99534cc35 100644 --- a/extensions/scarb-doc/src/db.rs +++ b/extensions/scarb-doc/src/db.rs @@ -1,5 +1,5 @@ use cairo_lang_compiler::project::{update_crate_roots_from_project_config, ProjectConfig}; -use cairo_lang_defs::db::{try_ext_as_virtual_impl, DefsDatabase, DefsGroup}; +use cairo_lang_defs::db::{init_defs_group, try_ext_as_virtual_impl, DefsDatabase, DefsGroup}; use cairo_lang_doc::db::{DocDatabase, DocGroup}; use cairo_lang_filesystem::cfg::{Cfg, CfgSet}; use cairo_lang_filesystem::db::{ @@ -8,7 +8,9 @@ use cairo_lang_filesystem::db::{ use cairo_lang_filesystem::ids::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::{ + init_semantic_group, PluginSuiteInput, SemanticDatabase, SemanticGroup, +}; use cairo_lang_semantic::inline_macros::get_default_plugin_suite; use cairo_lang_semantic::plugin::PluginSuite; use cairo_lang_starknet::starknet_plugin_suite; @@ -44,10 +46,13 @@ impl ScarbDocDatabase { }; init_files_group(&mut db); + init_defs_group(&mut db); + init_semantic_group(&mut db); db.set_cfg_set(Self::initial_cfg_set().into()); - db.apply_plugin_suite(plugin_suite); + let interned_plugin_suite = db.intern_plugin_suite(plugin_suite); + db.set_default_plugins_from_suite(interned_plugin_suite); if let Some(config) = project_config { db.apply_project_config(config); @@ -60,12 +65,6 @@ impl ScarbDocDatabase { CfgSet::from_iter([Cfg::name("doc")]) } - fn apply_plugin_suite(&mut self, plugin_suite: PluginSuite) { - self.set_macro_plugins(plugin_suite.plugins); - self.set_inline_macro_plugins(plugin_suite.inline_macro_plugins.into()); - self.set_analyzer_plugins(plugin_suite.analyzer_plugins); - } - fn apply_project_config(&mut self, config: ProjectConfig) { update_crate_roots_from_project_config(self, &config); } diff --git a/scarb/src/compiler/compilers/lib.rs b/scarb/src/compiler/compilers/lib.rs index 9c0f1b578..e22013d10 100644 --- a/scarb/src/compiler/compilers/lib.rs +++ b/scarb/src/compiler/compilers/lib.rs @@ -2,6 +2,9 @@ use anyhow::{Context, Result}; use cairo_lang_compiler::db::RootDatabase; use cairo_lang_compiler::CompilerConfig; use cairo_lang_defs::db::DefsGroup; +use cairo_lang_defs::plugin::MacroPlugin; +use cairo_lang_filesystem::db::FilesGroup; +use cairo_lang_filesystem::ids::CrateLongId; use cairo_lang_sierra::program::VersionedProgram; use cairo_lang_sierra_to_casm::compiler::SierraToCasmConfig; use cairo_lang_sierra_to_casm::metadata::{calc_metadata, calc_metadata_ap_change_only}; @@ -145,15 +148,22 @@ fn validate_compiler_config( unit: &CairoCompilationUnit, ws: &Workspace<'_>, ) { + let main_component = unit.main_component(); + let main_crate_id = db.intern_crate(CrateLongId::Real { + name: main_component.target_name(), + discriminator: main_component.id.to_discriminator(), + }); + // Generally, lib target compilation should be driven by a certain objective (e.g. cairo-run, // test framework, etc.), expressed by the plugin set with executables definition. // This does not apply to debug build (expressed by `replace_ids` flag), // which is a goal by itself. // See starkware-libs/cairo#5440 for more context. - let executable_plugin = db - .macro_plugins() - .iter() - .any(|plugin| !plugin.executable_attributes().is_empty()); + let executable_plugin = db.crate_macro_plugins(main_crate_id).iter().any(|&plugin| { + !db.lookup_intern_macro_plugin(plugin) + .executable_attributes() + .is_empty() + }); if !executable_plugin && !compiler_config.replace_ids { ws.config().ui().warn(formatdoc! {r#" artefacts produced by this build may be hard to utilize due to the build configuration diff --git a/scarb/src/compiler/db.rs b/scarb/src/compiler/db.rs index 429dd5813..6525ff423 100644 --- a/scarb/src/compiler/db.rs +++ b/scarb/src/compiler/db.rs @@ -58,13 +58,13 @@ fn load_plugins( let package_id = plugin_info.package.id; let plugin = ws.config().cairo_plugins().fetch(package_id)?; let instance = plugin.instantiate()?; - builder.with_plugin_suite(instance.plugin_suite()); + builder.with_default_plugin_suite(instance.plugin_suite()); } else { proc_macros.register(plugin_info.package.clone(), ws.config())?; } } let macro_host = Arc::new(proc_macros.into_plugin()?); - builder.with_plugin_suite(ProcMacroHostPlugin::build_plugin_suite(macro_host.clone())); + builder.with_default_plugin_suite(ProcMacroHostPlugin::build_plugin_suite(macro_host.clone())); Ok(macro_host) } @@ -198,10 +198,15 @@ fn build_project_config(unit: &CairoCompilationUnit) -> Result { Ok(project_config) } -pub(crate) fn has_starknet_plugin(db: &RootDatabase) -> bool { - db.macro_plugins() +pub(crate) fn has_starknet_plugin(db: &RootDatabase, component: &CompilationUnitComponent) -> bool { + let crate_id = db.intern_crate(CrateLongId::Real { + name: component.target_name(), + discriminator: component.id.to_discriminator(), + }); + + db.crate_macro_plugins(crate_id) .iter() - .any(|plugin| is_starknet_plugin(&**plugin)) + .any(|&plugin| is_starknet_plugin(&db.lookup_intern_macro_plugin(plugin))) } fn is_starknet_plugin(plugin: &dyn MacroPlugin) -> bool { diff --git a/scarb/src/ops/compile.rs b/scarb/src/ops/compile.rs index 3e63617e8..e41c18528 100644 --- a/scarb/src/ops/compile.rs +++ b/scarb/src/ops/compile.rs @@ -302,7 +302,7 @@ fn check_starknet_dependency( // I think we can get away with emitting false positives for users who write raw contracts // without using Starknet code generators. Such people shouldn't do what they do 😁 if unit.main_component().target_kind() == TargetKind::STARKNET_CONTRACT - && !has_starknet_plugin(db) + && !has_starknet_plugin(db, unit.main_component()) { ws.config().ui().warn(formatdoc! { r#" diff --git a/scarb/src/ops/proc_macro_server/methods/defined_macros.rs b/scarb/src/ops/proc_macro_server/methods/defined_macros.rs index 8004a0d7c..923c67b2d 100644 --- a/scarb/src/ops/proc_macro_server/methods/defined_macros.rs +++ b/scarb/src/ops/proc_macro_server/methods/defined_macros.rs @@ -1,8 +1,10 @@ use std::sync::Arc; use anyhow::Result; +use cairo_lang_utils::ordered_hash_map::OrderedHashMap; +use itertools::Itertools; use scarb_proc_macro_server_types::methods::defined_macros::{ - DefinedMacros, DefinedMacrosResponse, + DefinedMacros, DefinedMacrosCrateInfo, DefinedMacrosResponse, }; use super::Handler; @@ -13,37 +15,52 @@ impl Handler for DefinedMacros { proc_macro_host: Arc, _params: Self::Params, ) -> Result { - let mut response = proc_macro_host + let crate_macro_info = proc_macro_host .macros() .iter() - .map(|e| DefinedMacrosResponse { - attributes: e.declared_attributes(), - inline_macros: e.inline_macros(), - derives: e.declared_derives(), - executables: e.executable_attributes(), - }) - .reduce(|mut acc, defined_macros| { - acc.attributes.extend(defined_macros.attributes); - acc.inline_macros.extend(defined_macros.inline_macros); - acc.derives.extend(defined_macros.derives); - acc.executables.extend(defined_macros.executables); + .map(|macro_instance| { + let attributes = macro_instance + .declared_attributes() + .into_iter() + .sorted() + .dedup() + .collect(); - acc - }) - .unwrap_or_default(); + let inline_macros = macro_instance + .inline_macros() + .into_iter() + .sorted() + .dedup() + .collect(); - response.attributes.sort(); - response.attributes.dedup(); + let derives = macro_instance + .declared_attributes() + .into_iter() + .sorted() + .dedup() + .collect(); - response.inline_macros.sort(); - response.inline_macros.dedup(); + let executables = macro_instance + .executable_attributes() + .into_iter() + .sorted() + .dedup() + .collect(); - response.derives.sort(); - response.derives.dedup(); + let package_name = macro_instance.package_id().name.to_smol_str(); - response.executables.sort(); - response.executables.dedup(); + ( + package_name, + DefinedMacrosCrateInfo { + attributes, + inline_macros, + derives, + executables, + }, + ) + }) + .collect::>(); - Ok(response) + Ok(DefinedMacrosResponse { crate_macro_info }) } } diff --git a/scarb/tests/proc_macro_server.rs b/scarb/tests/proc_macro_server.rs index b01f865dc..8fdbc70ae 100644 --- a/scarb/tests/proc_macro_server.rs +++ b/scarb/tests/proc_macro_server.rs @@ -37,11 +37,17 @@ fn defined_macros() { let response = proc_macro_server .request_and_wait::(DefinedMacrosParams {}) .unwrap(); + let response = response.crate_macro_info; - assert_eq!(response.attributes, vec!["some".to_string()]); - assert_eq!(response.derives, vec!["some_derive".to_string()]); - assert_eq!(response.inline_macros, vec!["inline_some".to_string()]); - assert_eq!(response.executables, vec!["some_executable".to_string()]); + let packages = response.keys().collect::>(); + assert_eq!(packages.len(), 1); + assert_eq!(packages[0], "test_package"); + + let crate_macros = &response["test_package"]; + assert_eq!(&crate_macros.attributes, &["some".to_string()]); + assert_eq!(&crate_macros.derives, &["some_derive".to_string()]); + assert_eq!(&crate_macros.inline_macros, &["inline_some".to_string()]); + assert_eq!(&crate_macros.executables, &["some_executable".to_string()]); } #[test] diff --git a/utils/scarb-proc-macro-server-types/Cargo.toml b/utils/scarb-proc-macro-server-types/Cargo.toml index 6263e831e..f5ad03345 100644 --- a/utils/scarb-proc-macro-server-types/Cargo.toml +++ b/utils/scarb-proc-macro-server-types/Cargo.toml @@ -11,5 +11,8 @@ repository.workspace = true [dependencies] cairo-lang-macro = { version = "0.1", features = ["serde"] } +cairo-lang-semantic.workspace = true +cairo-lang-utils.workspace = true serde.workspace = true serde_json.workspace = true +smol_str.workspace = true diff --git a/utils/scarb-proc-macro-server-types/src/methods/defined_macros.rs b/utils/scarb-proc-macro-server-types/src/methods/defined_macros.rs index 9ad3db791..b6f12f42d 100644 --- a/utils/scarb-proc-macro-server-types/src/methods/defined_macros.rs +++ b/utils/scarb-proc-macro-server-types/src/methods/defined_macros.rs @@ -1,11 +1,19 @@ use super::Method; +use cairo_lang_utils::ordered_hash_map::OrderedHashMap; use serde::{Deserialize, Serialize}; +use smol_str::SmolStr; + +/// Response structure containing a mapping from package names to the information about the macros they use. +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct DefinedMacrosResponse { + pub crate_macro_info: OrderedHashMap, +} /// Response structure containing lists of all defined macros supported. /// /// Details the types of macros that can be expanded, such as attributes, inline macros, and derives. #[derive(Debug, Default, Serialize, Deserialize)] -pub struct DefinedMacrosResponse { +pub struct DefinedMacrosCrateInfo { /// List of attribute macro names available. pub attributes: Vec, /// List of inline macro names available.