diff --git a/Cargo.lock b/Cargo.lock index 39302c44fbc..9db23276aec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -525,6 +525,7 @@ dependencies = [ "cairo-lang-utils", "indoc", "salsa", + "semver", "smol_str", "thiserror", ] @@ -607,6 +608,7 @@ dependencies = [ "env_logger", "path-clean", "salsa", + "semver", "serde", "serde_json", "smol_str", diff --git a/Cargo.toml b/Cargo.toml index 55d9bcd36d3..569e69df2e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,6 +122,7 @@ rayon = "1.10.0" rstest = "0.19.0" salsa = "0.16.1" schemars = { version = "0.8.19", features = ["preserve_order"] } +semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0.200", default-features = false, features = ["derive"] } serde_json = "1.0.116" sha2 = "0.10.8" diff --git a/corelib/cairo_project.toml b/corelib/cairo_project.toml index 1d476297699..a262686b4f4 100644 --- a/corelib/cairo_project.toml +++ b/corelib/cairo_project.toml @@ -2,6 +2,7 @@ core = "src" [config.global] +version = "2.7.1" edition = "2024_07" [config.global.experimental_features] diff --git a/crates/cairo-lang-compiler/Cargo.toml b/crates/cairo-lang-compiler/Cargo.toml index 1cbd8fc2074..8fac5481d8d 100644 --- a/crates/cairo-lang-compiler/Cargo.toml +++ b/crates/cairo-lang-compiler/Cargo.toml @@ -21,6 +21,7 @@ cairo-lang-syntax = { path = "../cairo-lang-syntax", version = "~2.7.1" } cairo-lang-utils = { path = "../cairo-lang-utils", version = "~2.7.1" } indoc.workspace = true salsa.workspace = true +semver.workspace = true smol_str.workspace = true thiserror.workspace = true diff --git a/crates/cairo-lang-compiler/src/db.rs b/crates/cairo-lang-compiler/src/db.rs index f139bd92c15..9ea7b152eb0 100644 --- a/crates/cairo-lang-compiler/src/db.rs +++ b/crates/cairo-lang-compiler/src/db.rs @@ -1,16 +1,16 @@ use std::sync::Arc; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use cairo_lang_defs::db::{DefsDatabase, DefsGroup}; use cairo_lang_defs::plugin::{InlineMacroExprPlugin, MacroPlugin}; use cairo_lang_filesystem::cfg::CfgSet; use cairo_lang_filesystem::db::{ init_dev_corelib, init_files_group, AsFilesGroupMut, FilesDatabase, FilesGroup, FilesGroupEx, - CORELIB_CRATE_NAME, + CORELIB_CRATE_NAME, CORELIB_VERSION, }; use cairo_lang_filesystem::detect::detect_corelib; use cairo_lang_filesystem::flag::Flag; -use cairo_lang_filesystem::ids::FlagId; +use cairo_lang_filesystem::ids::{CrateLongId, FlagId}; use cairo_lang_lowering::db::{init_lowering_group, LoweringDatabase, LoweringGroup}; use cairo_lang_parser::db::{ParserDatabase, ParserGroup}; use cairo_lang_project::ProjectConfig; @@ -20,7 +20,7 @@ use cairo_lang_semantic::plugin::{AnalyzerPlugin, PluginSuite}; use cairo_lang_sierra_generator::db::SierraGenDatabase; use cairo_lang_syntax::node::db::{SyntaxDatabase, SyntaxGroup}; use cairo_lang_utils::ordered_hash_map::OrderedHashMap; -use cairo_lang_utils::Upcast; +use cairo_lang_utils::{Intern, Upcast}; use crate::project::{update_crate_root, update_crate_roots_from_project_config}; use crate::InliningStrategy; @@ -170,11 +170,36 @@ impl RootDatabaseBuilder { update_crate_root(&mut db, config, CORELIB_CRATE_NAME.into(), corelib.clone()); } } + validate_corelib(&db)?; Ok(db) } } +/// Validates that the corelib version matches the expected one. +fn validate_corelib(db: &RootDatabase) -> Result<()> { + let Some(config) = db.crate_config(CrateLongId::Real(CORELIB_CRATE_NAME.into()).intern(db)) + else { + return Ok(()); + }; + let Some(found) = config.settings.version else { + return Ok(()); + }; + let Ok(expected) = semver::Version::parse(CORELIB_VERSION) else { + return Ok(()); + }; + if found == expected { + return Ok(()); + } + let path_part = match config.root { + cairo_lang_filesystem::ids::Directory::Real(path) => { + format!(" for `{}`", path.to_string_lossy()) + } + cairo_lang_filesystem::ids::Directory::Virtual { .. } => "".to_string(), + }; + bail!("Corelib version mismatch: expected `{expected}`, found `{found}`{path_part}."); +} + impl AsFilesGroupMut for RootDatabase { fn as_files_group_mut(&mut self) -> &mut (dyn FilesGroup + 'static) { self diff --git a/crates/cairo-lang-filesystem/Cargo.toml b/crates/cairo-lang-filesystem/Cargo.toml index 29eecd373ae..4d260e05e14 100644 --- a/crates/cairo-lang-filesystem/Cargo.toml +++ b/crates/cairo-lang-filesystem/Cargo.toml @@ -11,6 +11,7 @@ cairo-lang-debug = { path = "../cairo-lang-debug", version = "~2.7.1" } cairo-lang-utils = { path = "../cairo-lang-utils", version = "~2.7.1", features = ["serde"] } path-clean.workspace = true salsa.workspace = true +semver.workspace = true serde = { workspace = true, default-features = true } smol_str.workspace = true diff --git a/crates/cairo-lang-filesystem/src/db.rs b/crates/cairo-lang-filesystem/src/db.rs index 31bd135662f..08b9eede342 100644 --- a/crates/cairo-lang-filesystem/src/db.rs +++ b/crates/cairo-lang-filesystem/src/db.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use cairo_lang_utils::ordered_hash_map::OrderedHashMap; use cairo_lang_utils::{Intern, LookupIntern, Upcast}; +use semver::Version; use serde::{Deserialize, Serialize}; use crate::cfg::CfgSet; @@ -18,6 +19,7 @@ use crate::span::{FileSummary, TextOffset, TextSpan, TextWidth}; mod test; pub const CORELIB_CRATE_NAME: &str = "core"; +pub const CORELIB_VERSION: &str = env!("CARGO_PKG_VERSION"); /// A configuration per crate. #[derive(Clone, Debug, Hash, PartialEq, Eq)] @@ -38,6 +40,8 @@ impl CrateConfiguration { pub struct CrateSettings { /// The crate's Cairo edition. pub edition: Edition, + /// The crate's version. + pub version: Option, pub cfg_set: Option, @@ -164,6 +168,7 @@ pub fn init_dev_corelib(db: &mut (dyn FilesGroup + 'static), core_lib_dir: PathB root: Directory::Real(core_lib_dir), settings: CrateSettings { edition: Edition::V2024_07, + version: Version::parse(CORELIB_VERSION).ok(), cfg_set: Default::default(), experimental_features: ExperimentalFeaturesConfig { negative_impls: true, diff --git a/crates/cairo-lang-language-server/src/project/scarb/db.rs b/crates/cairo-lang-language-server/src/project/scarb/db.rs index af3f25bf056..2124ece773a 100644 --- a/crates/cairo-lang-language-server/src/project/scarb/db.rs +++ b/crates/cairo-lang-language-server/src/project/scarb/db.rs @@ -65,6 +65,7 @@ pub fn update_crate_roots(metadata: &Metadata, db: &mut AnalysisDatabase) { let settings = CrateSettings { edition: scarb_package_edition(&package, crate_name), + version: package.map(|p| p.version.clone()), cfg_set: scarb_cfg_set_to_cairo( component.cfg.as_ref().unwrap_or(&compilation_unit.cfg), crate_name, diff --git a/crates/cairo-lang-project/src/test.rs b/crates/cairo-lang-project/src/test.rs index 45af138b9c3..364f2e38e5e 100644 --- a/crates/cairo-lang-project/src/test.rs +++ b/crates/cairo-lang-project/src/test.rs @@ -17,6 +17,7 @@ fn test_serde() { crates_config: AllCratesConfig { global: CrateSettings { edition: Default::default(), + version: Default::default(), experimental_features: ExperimentalFeaturesConfig::default(), cfg_set: Default::default(), }, @@ -25,6 +26,7 @@ fn test_serde() { "crate1".into(), CrateSettings { edition: Edition::V2023_10, + version: Default::default(), experimental_features: ExperimentalFeaturesConfig::default(), cfg_set: Default::default(), }, @@ -33,6 +35,7 @@ fn test_serde() { "crate3".into(), CrateSettings { edition: Default::default(), + version: Default::default(), experimental_features: ExperimentalFeaturesConfig { negative_impls: true, coupons: false, diff --git a/crates/cairo-lang-semantic/src/test_utils.rs b/crates/cairo-lang-semantic/src/test_utils.rs index c2d4588ba56..faa75a0d5e3 100644 --- a/crates/cairo-lang-semantic/src/test_utils.rs +++ b/crates/cairo-lang-semantic/src/test_utils.rs @@ -139,6 +139,7 @@ pub fn setup_test_crate_ex( } else { CrateSettings { edition: Edition::default(), + version: None, experimental_features: ExperimentalFeaturesConfig { negative_impls: true, coupons: true,