From a980eed1185f3ca2563c40e954e342ac08eb69a1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Mar 2024 16:44:05 -0600 Subject: [PATCH 1/4] refactor(schema): Make manifest its own directory --- crates/cargo-util-schemas/src/{manifest.rs => manifest/mod.rs} | 0 triagebot.toml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename crates/cargo-util-schemas/src/{manifest.rs => manifest/mod.rs} (100%) diff --git a/crates/cargo-util-schemas/src/manifest.rs b/crates/cargo-util-schemas/src/manifest/mod.rs similarity index 100% rename from crates/cargo-util-schemas/src/manifest.rs rename to crates/cargo-util-schemas/src/manifest/mod.rs diff --git a/triagebot.toml b/triagebot.toml index ab134f19721..b659dee749d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -171,7 +171,7 @@ trigger_files = ["src/cargo/core/compiler/lto.rs"] [autolabel."A-manifest"] trigger_files = [ - "crates/cargo-util-schemas/src/manifest.rs", + "crates/cargo-util-schemas/src/manifest/", "src/cargo/core/manifest.rs", "src/cargo/util/toml/mod.rs", "src/cargo/util/toml_mut/", From 46584a4d6be2d93f6f6b0ffd9d58170f3aef8112 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Mar 2024 16:45:58 -0600 Subject: [PATCH 2/4] refactor(schema): Pull RustVersion out into a mod --- crates/cargo-util-schemas/src/manifest/mod.rs | 79 +----------------- .../src/manifest/rust_version.rs | 80 +++++++++++++++++++ 2 files changed, 84 insertions(+), 75 deletions(-) create mode 100644 crates/cargo-util-schemas/src/manifest/rust_version.rs diff --git a/crates/cargo-util-schemas/src/manifest/mod.rs b/crates/cargo-util-schemas/src/manifest/mod.rs index f6d131f533d..75f7f628bef 100644 --- a/crates/cargo-util-schemas/src/manifest/mod.rs +++ b/crates/cargo-util-schemas/src/manifest/mod.rs @@ -16,11 +16,13 @@ use serde::{Deserialize, Serialize}; use serde_untagged::UntaggedEnumVisitor; use crate::core::PackageIdSpec; -use crate::core::PartialVersion; -use crate::core::PartialVersionError; use crate::restricted_names; +mod rust_version; + pub use crate::restricted_names::NameValidationError; +pub use rust_version::RustVersion; +pub use rust_version::RustVersionError; /// This type is used to deserialize `Cargo.toml` files. #[derive(Debug, Deserialize, Serialize)] @@ -1399,79 +1401,6 @@ pub enum TomlLintLevel { Allow, } -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug, serde::Serialize)] -#[serde(transparent)] -pub struct RustVersion(PartialVersion); - -impl std::ops::Deref for RustVersion { - type Target = PartialVersion; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::str::FromStr for RustVersion { - type Err = RustVersionError; - - fn from_str(value: &str) -> Result { - let partial = value.parse::(); - let partial = partial.map_err(RustVersionErrorKind::PartialVersion)?; - partial.try_into() - } -} - -impl TryFrom for RustVersion { - type Error = RustVersionError; - - fn try_from(partial: PartialVersion) -> Result { - if partial.pre.is_some() { - return Err(RustVersionErrorKind::Prerelease.into()); - } - if partial.build.is_some() { - return Err(RustVersionErrorKind::BuildMetadata.into()); - } - Ok(Self(partial)) - } -} - -impl<'de> serde::Deserialize<'de> for RustVersion { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - UntaggedEnumVisitor::new() - .expecting("SemVer version") - .string(|value| value.parse().map_err(serde::de::Error::custom)) - .deserialize(deserializer) - } -} - -impl Display for RustVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Error parsing a [`RustVersion`]. -#[derive(Debug, thiserror::Error)] -#[error(transparent)] -pub struct RustVersionError(#[from] RustVersionErrorKind); - -/// Non-public error kind for [`RustVersionError`]. -#[non_exhaustive] -#[derive(Debug, thiserror::Error)] -enum RustVersionErrorKind { - #[error("unexpected prerelease field, expected a version like \"1.32\"")] - Prerelease, - - #[error("unexpected build field, expected a version like \"1.32\"")] - BuildMetadata, - - #[error(transparent)] - PartialVersion(#[from] PartialVersionError), -} - #[derive(Copy, Clone, Debug)] pub struct InvalidCargoFeatures {} diff --git a/crates/cargo-util-schemas/src/manifest/rust_version.rs b/crates/cargo-util-schemas/src/manifest/rust_version.rs new file mode 100644 index 00000000000..6f76dab4a6e --- /dev/null +++ b/crates/cargo-util-schemas/src/manifest/rust_version.rs @@ -0,0 +1,80 @@ +use std::fmt; +use std::fmt::Display; + +use serde_untagged::UntaggedEnumVisitor; + +use crate::core::PartialVersion; +use crate::core::PartialVersionError; + +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug, serde::Serialize)] +#[serde(transparent)] +pub struct RustVersion(PartialVersion); + +impl std::ops::Deref for RustVersion { + type Target = PartialVersion; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::str::FromStr for RustVersion { + type Err = RustVersionError; + + fn from_str(value: &str) -> Result { + let partial = value.parse::(); + let partial = partial.map_err(RustVersionErrorKind::PartialVersion)?; + partial.try_into() + } +} + +impl TryFrom for RustVersion { + type Error = RustVersionError; + + fn try_from(partial: PartialVersion) -> Result { + if partial.pre.is_some() { + return Err(RustVersionErrorKind::Prerelease.into()); + } + if partial.build.is_some() { + return Err(RustVersionErrorKind::BuildMetadata.into()); + } + Ok(Self(partial)) + } +} + +impl<'de> serde::Deserialize<'de> for RustVersion { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + UntaggedEnumVisitor::new() + .expecting("SemVer version") + .string(|value| value.parse().map_err(serde::de::Error::custom)) + .deserialize(deserializer) + } +} + +impl Display for RustVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +/// Error parsing a [`RustVersion`]. +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct RustVersionError(#[from] RustVersionErrorKind); + +/// Non-public error kind for [`RustVersionError`]. +#[non_exhaustive] +#[derive(Debug, thiserror::Error)] +enum RustVersionErrorKind { + #[error("unexpected prerelease field, expected a version like \"1.32\"")] + Prerelease, + + #[error("unexpected build field, expected a version like \"1.32\"")] + BuildMetadata, + + #[error(transparent)] + PartialVersion(#[from] PartialVersionError), +} From 16168817711392c06fba4185c0ec00e8008f0072 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Mar 2024 21:20:34 -0600 Subject: [PATCH 3/4] refactor: Clarify some variable names --- src/cargo/ops/cargo_add/mod.rs | 9 +++++++-- src/cargo/ops/cargo_compile/mod.rs | 22 +++++++++++----------- src/cargo/util/toml/mod.rs | 22 +++++++++++----------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/cargo/ops/cargo_add/mod.rs b/src/cargo/ops/cargo_add/mod.rs index eeebddaf873..4979e208d24 100644 --- a/src/cargo/ops/cargo_add/mod.rs +++ b/src/cargo/ops/cargo_add/mod.rs @@ -702,11 +702,16 @@ ignoring {dependency}@{latest_version} (which requires rustc {latest_rust_versio /// - `msrvs` is sorted by version fn latest_compatible<'s>( msrvs: &[(&'s Summary, Option<&RustVersion>)], - req_msrv: &RustVersion, + pkg_msrv: &RustVersion, ) -> Option<&'s Summary> { msrvs .iter() - .filter(|(_, v)| v.as_ref().map(|msrv| req_msrv >= *msrv).unwrap_or(true)) + .filter(|(_, dep_msrv)| { + dep_msrv + .as_ref() + .map(|dep_msrv| pkg_msrv >= *dep_msrv) + .unwrap_or(true) + }) .map(|(s, _)| s) .last() .copied() diff --git a/src/cargo/ops/cargo_compile/mod.rs b/src/cargo/ops/cargo_compile/mod.rs index 4aaf4878712..e9c777cfc55 100644 --- a/src/cargo/ops/cargo_compile/mod.rs +++ b/src/cargo/ops/cargo_compile/mod.rs @@ -481,34 +481,34 @@ pub fn create_bcx<'a, 'gctx>( if honor_rust_version { // Remove any pre-release identifiers for easier comparison - let current_version = &target_data.rustc.version; - let untagged_version = semver::Version::new( - current_version.major, - current_version.minor, - current_version.patch, + let rustc_version = &target_data.rustc.version; + let rustc_version_untagged = semver::Version::new( + rustc_version.major, + rustc_version.minor, + rustc_version.patch, ); let mut incompatible = Vec::new(); let mut local_incompatible = false; for unit in unit_graph.keys() { - let Some(version) = unit.pkg.rust_version() else { + let Some(pkg_msrv) = unit.pkg.rust_version() else { continue; }; - let req = version.to_caret_req(); - if req.matches(&untagged_version) { + let pkg_msrv_req = pkg_msrv.to_caret_req(); + if pkg_msrv_req.matches(&rustc_version_untagged) { continue; } local_incompatible |= unit.is_local(); - incompatible.push((unit, version)); + incompatible.push((unit, pkg_msrv)); } if !incompatible.is_empty() { use std::fmt::Write as _; let plural = if incompatible.len() == 1 { "" } else { "s" }; let mut message = format!( - "rustc {current_version} is not supported by the following package{plural}:\n" + "rustc {rustc_version} is not supported by the following package{plural}:\n" ); incompatible.sort_by_key(|(unit, _)| (unit.pkg.name(), unit.pkg.version())); for (unit, msrv) in incompatible { @@ -529,7 +529,7 @@ pub fn create_bcx<'a, 'gctx>( &mut message, "Either upgrade rustc or select compatible dependency versions with `cargo update @ --precise ` -where `` is the latest version supporting rustc {current_version}", +where `` is the latest version supporting rustc {rustc_version}", ) .unwrap(); } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 1a01d59bd08..8258e2f8df0 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -580,17 +580,17 @@ pub fn to_real_manifest( .parse() .with_context(|| "failed to parse the `edition` key")?; package.edition = Some(manifest::InheritableField::Value(edition.to_string())); - if let Some(rust_version) = &rust_version { - let req = rust_version.to_caret_req(); - if let Some(first_version) = edition.first_version() { + if let Some(pkg_msrv) = &rust_version { + let pkg_msrv_req = pkg_msrv.to_caret_req(); + if let Some(edition_msrv) = edition.first_version() { let unsupported = - semver::Version::new(first_version.major, first_version.minor - 1, 9999); - if req.matches(&unsupported) { + semver::Version::new(edition_msrv.major, edition_msrv.minor - 1, 9999); + if pkg_msrv_req.matches(&unsupported) { bail!( "rust-version {} is older than first version ({}) required by \ the specified edition ({})", - rust_version, - first_version, + pkg_msrv, + edition_msrv, edition, ) } @@ -598,14 +598,14 @@ pub fn to_real_manifest( } edition } else { - let msrv_edition = if let Some(rust_version) = &rust_version { + let msrv_edition = if let Some(pkg_msrv) = &rust_version { Edition::ALL .iter() .filter(|e| { e.first_version() - .map(|e| { - let e = PartialVersion::from(e); - e <= **rust_version + .map(|edition_msrv| { + let edition_msrv = PartialVersion::from(edition_msrv); + edition_msrv <= **pkg_msrv }) .unwrap_or_default() }) From 134ed93f60b59fc555e3513f9bf35f15c513e109 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Mar 2024 21:22:28 -0600 Subject: [PATCH 4/4] fix: Consistently compare MSRVs We used several strategies - Relying in `impl Ord for RustVersion` - Converting to version requirements - Decrementing a version This consolidates around one strategy: `RustVersion::is_compatible_with` - Ensure the comparisons have the same behavior - Centralize knowledge of how to handle pre-release rustc - Losslessly allow comparing with either rustc or workspace msrv --- .../src/manifest/rust_version.rs | 99 ++++++++++++++++++- src/cargo/core/resolver/version_prefs.rs | 14 +-- src/cargo/ops/cargo_add/mod.rs | 18 +--- src/cargo/ops/cargo_compile/mod.rs | 11 +-- src/cargo/ops/cargo_install.rs | 13 +-- .../ops/common_for_install_and_uninstall.rs | 10 +- src/cargo/ops/resolve.rs | 3 +- src/cargo/util/toml/mod.rs | 13 +-- 8 files changed, 125 insertions(+), 56 deletions(-) diff --git a/crates/cargo-util-schemas/src/manifest/rust_version.rs b/crates/cargo-util-schemas/src/manifest/rust_version.rs index 6f76dab4a6e..03ba94b3e71 100644 --- a/crates/cargo-util-schemas/src/manifest/rust_version.rs +++ b/crates/cargo-util-schemas/src/manifest/rust_version.rs @@ -10,10 +10,25 @@ use crate::core::PartialVersionError; #[serde(transparent)] pub struct RustVersion(PartialVersion); -impl std::ops::Deref for RustVersion { - type Target = PartialVersion; +impl RustVersion { + pub fn is_compatible_with(&self, rustc: &PartialVersion) -> bool { + let msrv = self.0.to_caret_req(); + // Remove any pre-release identifiers for easier comparison + let rustc = semver::Version { + major: rustc.major, + minor: rustc.minor.unwrap_or_default(), + patch: rustc.patch.unwrap_or_default(), + pre: Default::default(), + build: Default::default(), + }; + msrv.matches(&rustc) + } + + pub fn into_partial(self) -> PartialVersion { + self.0 + } - fn deref(&self) -> &Self::Target { + pub fn as_partial(&self) -> &PartialVersion { &self.0 } } @@ -28,6 +43,15 @@ impl std::str::FromStr for RustVersion { } } +impl TryFrom for RustVersion { + type Error = RustVersionError; + + fn try_from(version: semver::Version) -> Result { + let version = PartialVersion::from(version); + Self::try_from(version) + } +} + impl TryFrom for RustVersion { type Error = RustVersionError; @@ -78,3 +102,72 @@ enum RustVersionErrorKind { #[error(transparent)] PartialVersion(#[from] PartialVersionError), } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn is_compatible_with_rustc() { + let cases = &[ + ("1", "1.70.0", true), + ("1.30", "1.70.0", true), + ("1.30.10", "1.70.0", true), + ("1.70", "1.70.0", true), + ("1.70.0", "1.70.0", true), + ("1.70.1", "1.70.0", false), + ("1.70", "1.70.0-nightly", true), + ("1.70.0", "1.70.0-nightly", true), + ("1.71", "1.70.0", false), + ("2", "1.70.0", false), + ]; + let mut passed = true; + for (msrv, rustc, expected) in cases { + let msrv: RustVersion = msrv.parse().unwrap(); + let rustc = PartialVersion::from(semver::Version::parse(rustc).unwrap()); + if msrv.is_compatible_with(&rustc) != *expected { + println!("failed: {msrv} is_compatible_with {rustc} == {expected}"); + passed = false; + } + } + assert!(passed); + } + + #[test] + fn is_compatible_with_workspace_msrv() { + let cases = &[ + ("1", "1", true), + ("1", "1.70", true), + ("1", "1.70.0", true), + ("1.30", "1", false), + ("1.30", "1.70", true), + ("1.30", "1.70.0", true), + ("1.30.10", "1", false), + ("1.30.10", "1.70", true), + ("1.30.10", "1.70.0", true), + ("1.70", "1", false), + ("1.70", "1.70", true), + ("1.70", "1.70.0", true), + ("1.70.0", "1", false), + ("1.70.0", "1.70", true), + ("1.70.0", "1.70.0", true), + ("1.70.1", "1", false), + ("1.70.1", "1.70", false), + ("1.70.1", "1.70.0", false), + ("1.71", "1", false), + ("1.71", "1.70", false), + ("1.71", "1.70.0", false), + ("2", "1.70.0", false), + ]; + let mut passed = true; + for (dep_msrv, ws_msrv, expected) in cases { + let dep_msrv: RustVersion = dep_msrv.parse().unwrap(); + let ws_msrv = ws_msrv.parse::().unwrap().into_partial(); + if dep_msrv.is_compatible_with(&ws_msrv) != *expected { + println!("failed: {dep_msrv} is_compatible_with {ws_msrv} == {expected}"); + passed = false; + } + } + assert!(passed); + } +} diff --git a/src/cargo/core/resolver/version_prefs.rs b/src/cargo/core/resolver/version_prefs.rs index 2d78f30862d..5e6cc230ffb 100644 --- a/src/cargo/core/resolver/version_prefs.rs +++ b/src/cargo/core/resolver/version_prefs.rs @@ -4,7 +4,7 @@ use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; -use cargo_util_schemas::manifest::RustVersion; +use cargo_util_schemas::core::PartialVersion; use crate::core::{Dependency, PackageId, Summary}; use crate::util::interning::InternedString; @@ -21,7 +21,7 @@ pub struct VersionPreferences { try_to_use: HashSet, prefer_patch_deps: HashMap>, version_ordering: VersionOrdering, - max_rust_version: Option, + max_rust_version: Option, } #[derive(Copy, Clone, Default, PartialEq, Eq, Hash, Debug)] @@ -49,7 +49,7 @@ impl VersionPreferences { self.version_ordering = ordering; } - pub fn max_rust_version(&mut self, ver: Option) { + pub fn max_rust_version(&mut self, ver: Option) { self.max_rust_version = ver; } @@ -92,8 +92,8 @@ impl VersionPreferences { (Some(a), Some(b)) if a == b => {} // Primary comparison (Some(a), Some(b)) => { - let a_is_compat = a <= max_rust_version; - let b_is_compat = b <= max_rust_version; + let a_is_compat = a.is_compatible_with(max_rust_version); + let b_is_compat = b.is_compatible_with(max_rust_version); match (a_is_compat, b_is_compat) { (true, true) => {} // fallback (false, false) => {} // fallback @@ -103,14 +103,14 @@ impl VersionPreferences { } // Prioritize `None` over incompatible (None, Some(b)) => { - if b <= max_rust_version { + if b.is_compatible_with(max_rust_version) { return Ordering::Greater; } else { return Ordering::Less; } } (Some(a), None) => { - if a <= max_rust_version { + if a.is_compatible_with(max_rust_version) { return Ordering::Less; } else { return Ordering::Greater; diff --git a/src/cargo/ops/cargo_add/mod.rs b/src/cargo/ops/cargo_add/mod.rs index 4979e208d24..61b12c7ac66 100644 --- a/src/cargo/ops/cargo_add/mod.rs +++ b/src/cargo/ops/cargo_add/mod.rs @@ -619,21 +619,13 @@ fn get_latest_dependency( let (req_msrv, is_msrv) = spec .rust_version() .cloned() - .map(|msrv| CargoResult::Ok((msrv.clone(), true))) + .map(|msrv| CargoResult::Ok((msrv.clone().into_partial(), true))) .unwrap_or_else(|| { let rustc = gctx.load_global_rustc(None)?; // Remove any pre-release identifiers for easier comparison - let current_version = &rustc.version; - let untagged_version = RustVersion::try_from(PartialVersion { - major: current_version.major, - minor: Some(current_version.minor), - patch: Some(current_version.patch), - pre: None, - build: None, - }) - .unwrap(); - Ok((untagged_version, false)) + let rustc_version = rustc.version.clone().into(); + Ok((rustc_version, false)) })?; let msrvs = possibilities @@ -702,14 +694,14 @@ ignoring {dependency}@{latest_version} (which requires rustc {latest_rust_versio /// - `msrvs` is sorted by version fn latest_compatible<'s>( msrvs: &[(&'s Summary, Option<&RustVersion>)], - pkg_msrv: &RustVersion, + pkg_msrv: &PartialVersion, ) -> Option<&'s Summary> { msrvs .iter() .filter(|(_, dep_msrv)| { dep_msrv .as_ref() - .map(|dep_msrv| pkg_msrv >= *dep_msrv) + .map(|dep_msrv| dep_msrv.is_compatible_with(pkg_msrv)) .unwrap_or(true) }) .map(|(s, _)| s) diff --git a/src/cargo/ops/cargo_compile/mod.rs b/src/cargo/ops/cargo_compile/mod.rs index e9c777cfc55..d413672e243 100644 --- a/src/cargo/ops/cargo_compile/mod.rs +++ b/src/cargo/ops/cargo_compile/mod.rs @@ -480,13 +480,7 @@ pub fn create_bcx<'a, 'gctx>( } if honor_rust_version { - // Remove any pre-release identifiers for easier comparison - let rustc_version = &target_data.rustc.version; - let rustc_version_untagged = semver::Version::new( - rustc_version.major, - rustc_version.minor, - rustc_version.patch, - ); + let rustc_version = target_data.rustc.version.clone().into(); let mut incompatible = Vec::new(); let mut local_incompatible = false; @@ -495,8 +489,7 @@ pub fn create_bcx<'a, 'gctx>( continue; }; - let pkg_msrv_req = pkg_msrv.to_caret_req(); - if pkg_msrv_req.matches(&rustc_version_untagged) { + if pkg_msrv.is_compatible_with(&rustc_version) { continue; } diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index ced0ea932b1..4e51ef30ea4 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -15,6 +15,7 @@ use crate::{drop_println, ops}; use anyhow::{bail, Context as _}; use cargo_util::paths; +use cargo_util_schemas::core::PartialVersion; use itertools::Itertools; use semver::VersionReq; use tempfile::Builder as TempFileBuilder; @@ -66,7 +67,7 @@ impl<'gctx> InstallablePackage<'gctx> { force: bool, no_track: bool, needs_update_if_source_is_index: bool, - current_rust_version: Option<&semver::Version>, + current_rust_version: Option<&PartialVersion>, ) -> CargoResult> { if let Some(name) = krate { if name == "." { @@ -625,15 +626,7 @@ pub fn install( let current_rust_version = if opts.honor_rust_version { let rustc = gctx.load_global_rustc(None)?; - - // Remove any pre-release identifiers for easier comparison - let current_version = &rustc.version; - let untagged_version = semver::Version::new( - current_version.major, - current_version.minor, - current_version.patch, - ); - Some(untagged_version) + Some(rustc.version.clone().into()) } else { None }; diff --git a/src/cargo/ops/common_for_install_and_uninstall.rs b/src/cargo/ops/common_for_install_and_uninstall.rs index 89705b3548b..c8d35ba6c56 100644 --- a/src/cargo/ops/common_for_install_and_uninstall.rs +++ b/src/cargo/ops/common_for_install_and_uninstall.rs @@ -8,6 +8,7 @@ use std::task::Poll; use anyhow::{bail, format_err, Context as _}; use cargo_util::paths; +use cargo_util_schemas::core::PartialVersion; use ops::FilterRule; use serde::{Deserialize, Serialize}; @@ -569,7 +570,7 @@ pub fn select_dep_pkg( dep: Dependency, gctx: &GlobalContext, needs_update: bool, - current_rust_version: Option<&semver::Version>, + current_rust_version: Option<&PartialVersion>, ) -> CargoResult where T: Source, @@ -596,8 +597,7 @@ where { Some(summary) => { if let (Some(current), Some(msrv)) = (current_rust_version, summary.rust_version()) { - let msrv_req = msrv.to_caret_req(); - if !msrv_req.matches(current) { + if !msrv.is_compatible_with(current) { let name = summary.name(); let ver = summary.version(); let extra = if dep.source_id().is_registry() { @@ -616,7 +616,7 @@ where .filter(|summary| { summary .rust_version() - .map(|msrv| msrv.to_caret_req().matches(current)) + .map(|msrv| msrv.is_compatible_with(current)) .unwrap_or(true) }) .max_by_key(|s| s.package_id()) @@ -689,7 +689,7 @@ pub fn select_pkg( dep: Option, mut list_all: F, gctx: &GlobalContext, - current_rust_version: Option<&semver::Version>, + current_rust_version: Option<&PartialVersion>, ) -> CargoResult where T: Source, diff --git a/src/cargo/ops/resolve.rs b/src/cargo/ops/resolve.rs index f9e036b2e05..71b386df3fe 100644 --- a/src/cargo/ops/resolve.rs +++ b/src/cargo/ops/resolve.rs @@ -73,6 +73,7 @@ use crate::util::cache_lock::CacheLockMode; use crate::util::errors::CargoResult; use crate::util::CanonicalUrl; use anyhow::Context as _; +use cargo_util_schemas::manifest::RustVersion; use std::collections::{HashMap, HashSet}; use tracing::{debug, trace}; @@ -318,7 +319,7 @@ pub fn resolve_with_previous<'gctx>( version_prefs.version_ordering(VersionOrdering::MinimumVersionsFirst) } if ws.gctx().cli_unstable().msrv_policy { - version_prefs.max_rust_version(ws.rust_version().cloned()); + version_prefs.max_rust_version(ws.rust_version().cloned().map(RustVersion::into_partial)); } // This is a set of PackageIds of `[patch]` entries, and some related locked PackageIds, for diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 8258e2f8df0..80910aecd36 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -9,7 +9,6 @@ use crate::AlreadyPrintedError; use anyhow::{anyhow, bail, Context as _}; use cargo_platform::Platform; use cargo_util::paths; -use cargo_util_schemas::core::PartialVersion; use cargo_util_schemas::manifest; use cargo_util_schemas::manifest::RustVersion; use itertools::Itertools; @@ -581,11 +580,9 @@ pub fn to_real_manifest( .with_context(|| "failed to parse the `edition` key")?; package.edition = Some(manifest::InheritableField::Value(edition.to_string())); if let Some(pkg_msrv) = &rust_version { - let pkg_msrv_req = pkg_msrv.to_caret_req(); if let Some(edition_msrv) = edition.first_version() { - let unsupported = - semver::Version::new(edition_msrv.major, edition_msrv.minor - 1, 9999); - if pkg_msrv_req.matches(&unsupported) { + let edition_msrv = RustVersion::try_from(edition_msrv).unwrap(); + if !edition_msrv.is_compatible_with(pkg_msrv.as_partial()) { bail!( "rust-version {} is older than first version ({}) required by \ the specified edition ({})", @@ -603,9 +600,9 @@ pub fn to_real_manifest( .iter() .filter(|e| { e.first_version() - .map(|edition_msrv| { - let edition_msrv = PartialVersion::from(edition_msrv); - edition_msrv <= **pkg_msrv + .map(|e| { + let e = RustVersion::try_from(e).unwrap(); + e.is_compatible_with(pkg_msrv.as_partial()) }) .unwrap_or_default() })