diff --git a/Cargo.lock b/Cargo.lock index 4a1f95980820d..ee14ea69138a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -217,9 +217,9 @@ dependencies = [ [[package]] name = "astral-pubgrub" -version = "0.3.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6cb15b4f5096a3a1b41fdc2736a1c33d87c78f34d3c1ec2b669e766edadd559" +checksum = "c79d771681f6c21ebe25dda598774b6e6badca8b720ce2168df7788b2821c46d" dependencies = [ "astral-version-ranges", "indexmap", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "astral-version-ranges" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31979bc305610246d78ac01d63467a12d8454c6e3b8b22b5811d343a1198dfbb" +checksum = "086f936efdefab117f5a72367fb3d68c4fded8ba5a7008e3c63365eecf723822" dependencies = [ "smallvec", ] diff --git a/Cargo.toml b/Cargo.toml index 3fe444de5b805..89f31f3bf4a32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -189,7 +189,7 @@ percent-encoding = { version = "2.3.1" } petgraph = { version = "0.8.0" } proc-macro2 = { version = "1.0.86" } procfs = { version = "0.18.0", default-features = false, features = ["flate2"] } -pubgrub = { version = "0.3.3", package = "astral-pubgrub" } +pubgrub = { version = "0.5.0", package = "astral-pubgrub" } quote = { version = "1.0.37" } rand = { version = "0.9.4" } rayon = { version = "1.10.0" } @@ -289,7 +289,7 @@ unicode-width = { version = "0.2.0" } unscanny = { version = "0.1.0" } url = { version = "2.5.2", features = ["serde"] } uuid = { version = "1.16.0" } -version-ranges = { version = "0.1.3", package = "astral-version-ranges" } +version-ranges = { version = "0.2.0", package = "astral-version-ranges" } walkdir = { version = "2.5.0" } webpki-root-certs = { version = "1" } which = { version = "8.0.0", features = ["regex"] } diff --git a/crates/uv-pep440/src/version_specifier.rs b/crates/uv-pep440/src/version_specifier.rs index 02f83da9ccc58..8ea5baa07180e 100644 --- a/crates/uv-pep440/src/version_specifier.rs +++ b/crates/uv-pep440/src/version_specifier.rs @@ -83,7 +83,7 @@ impl VersionSpecifiers { /// /// This function is not applicable to ranges involving pre-release versions. pub fn from_release_only_bounds<'a>( - mut bounds: impl Iterator, &'a Bound)>, + mut bounds: impl Iterator, Bound<&'a Version>)>, ) -> Self { let mut specifiers = Vec::new(); @@ -552,7 +552,7 @@ impl VersionSpecifier { /// /// This function is not applicable to ranges involving pre-release versions. pub fn from_release_only_bounds( - bounds: (&Bound, &Bound), + bounds: (Bound<&Version>, Bound<&Version>), ) -> impl Iterator { let (b1, b2) = match bounds { (Bound::Included(v1), Bound::Included(v2)) if v1 == v2 => { @@ -572,8 +572,8 @@ impl VersionSpecifier { (Some(Self::equals_star_version(version)), None) } _ => ( - Self::from_lower_bound(&Bound::Included(v1.clone())), - Self::from_upper_bound(&Bound::Excluded(v2.clone())), + Self::from_lower_bound(Bound::Included(v1)), + Self::from_upper_bound(Bound::Excluded(v2)), ), } } @@ -584,7 +584,7 @@ impl VersionSpecifier { } /// Returns a version specifier representing the given lower bound. - fn from_lower_bound(bound: &Bound) -> Option { + fn from_lower_bound(bound: Bound<&Version>) -> Option { match bound { Bound::Included(version) => { Some(Self::from_version(Operator::GreaterThanEqual, version.clone()).unwrap()) @@ -597,7 +597,7 @@ impl VersionSpecifier { } /// Returns a version specifier representing the given upper bound. - fn from_upper_bound(bound: &Bound) -> Option { + fn from_upper_bound(bound: Bound<&Version>) -> Option { match bound { Bound::Included(version) => { Some(Self::from_version(Operator::LessThanEqual, version.clone()).unwrap()) diff --git a/crates/uv-pep508/src/marker/algebra.rs b/crates/uv-pep508/src/marker/algebra.rs index df467321292ce..700e9959015cb 100644 --- a/crates/uv-pep508/src/marker/algebra.rs +++ b/crates/uv-pep508/src/marker/algebra.rs @@ -1438,13 +1438,13 @@ impl Edges { // Add the `true` edges. for (start, end) in range.iter() { - let range = Ranges::from_range_bounds((start.clone(), end.clone())); + let range = Ranges::from_range_bounds((start.cloned(), end.cloned())); edges.push((range, NodeId::TRUE)); } // Add the `false` edges. for (start, end) in range.complement().iter() { - let range = Ranges::from_range_bounds((start.clone(), end.clone())); + let range = Ranges::from_range_bounds((start.cloned(), end.cloned())); edges.push((range, NodeId::FALSE)); } diff --git a/crates/uv-pep508/src/marker/tree.rs b/crates/uv-pep508/src/marker/tree.rs index 8da6fde444ce4..3ee4d7dc38472 100644 --- a/crates/uv-pep508/src/marker/tree.rs +++ b/crates/uv-pep508/src/marker/tree.rs @@ -305,7 +305,7 @@ impl MarkerOperator { /// Returns the marker operator and value whose union represents the given range. pub(crate) fn from_bounds( - bounds: (&Bound, &Bound), + bounds: (Bound<&ArcStr>, Bound<&ArcStr>), ) -> impl Iterator { let (b1, b2) = match bounds { (Bound::Included(v1), Bound::Included(v2)) if v1 == v2 => { @@ -321,7 +321,7 @@ impl MarkerOperator { } /// Returns a value specifier representing the given lower bound. - fn from_lower_bound(bound: &Bound) -> Option<(Self, ArcStr)> { + fn from_lower_bound(bound: Bound<&ArcStr>) -> Option<(Self, ArcStr)> { match bound { Bound::Included(value) => Some((Self::GreaterEqual, value.clone())), Bound::Excluded(value) => Some((Self::GreaterThan, value.clone())), @@ -330,7 +330,7 @@ impl MarkerOperator { } /// Returns a value specifier representing the given upper bound. - fn from_upper_bound(bound: &Bound) -> Option<(Self, ArcStr)> { + fn from_upper_bound(bound: Bound<&ArcStr>) -> Option<(Self, ArcStr)> { match bound { Bound::Included(value) => Some((Self::LessEqual, value.clone())), Bound::Excluded(value) => Some((Self::LessThan, value.clone())), diff --git a/crates/uv-resolver/src/error.rs b/crates/uv-resolver/src/error.rs index eee9f5650db33..1bcbfe86acf9d 100644 --- a/crates/uv-resolver/src/error.rs +++ b/crates/uv-resolver/src/error.rs @@ -1315,7 +1315,7 @@ impl SentinelRange<'_> { pub fn strip(&self) -> Ranges { self.0 .iter() - .map(|(lower, upper)| Self::strip_sentinel(lower.clone(), upper.clone())) + .map(|(lower, upper)| Self::strip_sentinel(lower.cloned(), upper.cloned())) .collect() } @@ -1406,7 +1406,7 @@ impl<'a> PrefixMatch<'a> { /// /// Prefix matches are desugared to (e.g.) `>=2.4.dev0,<2.5.dev0`, but we want to render them /// as `==2.4.*` in error messages. - pub(crate) fn from_range(lower: &'a Bound, upper: &'a Bound) -> Option { + pub(crate) fn from_range(lower: Bound<&'a Version>, upper: Bound<&'a Version>) -> Option { let Bound::Included(lower) = lower else { return None; }; diff --git a/crates/uv-resolver/src/pubgrub/report.rs b/crates/uv-resolver/src/pubgrub/report.rs index e824b3d435dc8..2950b0546596f 100644 --- a/crates/uv-resolver/src/pubgrub/report.rs +++ b/crates/uv-resolver/src/pubgrub/report.rs @@ -2380,7 +2380,7 @@ fn update_availability_range( range .iter() .filter_map(|(lower, upper)| { - let segment_range = Range::from_range_bounds((lower.clone(), upper.clone())); + let segment_range = Range::from_range_bounds((lower.cloned(), upper.cloned())); // Drop the segment if it's disjoint with the available range, e.g., if the segment is // `foo>999`, and the available versions are all `<10` it's useless to show. @@ -2412,13 +2412,13 @@ fn update_availability_range( Bound::Included(version) if !version_contained_in(version, available_versions) => { Bound::Excluded(version.clone()) } - _ => (*lower).clone(), + _ => lower.cloned(), }; let upper = match upper { Bound::Included(version) if !version_contained_in(version, available_versions) => { Bound::Excluded(version.clone()) } - _ => (*upper).clone(), + _ => upper.cloned(), }; Some((lower, upper)) @@ -2477,7 +2477,7 @@ impl std::fmt::Display for PackageRange<'_> { } } (Bound::Included(v), Bound::Excluded(b)) => { - if let Some(prefix) = PrefixMatch::from_range(lower, upper) { + if let Some(prefix) = PrefixMatch::from_range(*lower, *upper) { write!(f, "{package}{prefix}")?; } else { write!(f, "{package}>={v},<{b}")?; diff --git a/crates/uv-resolver/src/resolver/derivation.rs b/crates/uv-resolver/src/resolver/derivation.rs index 0ecd081f13f57..47911d5a38b05 100644 --- a/crates/uv-resolver/src/resolver/derivation.rs +++ b/crates/uv-resolver/src/resolver/derivation.rs @@ -1,4 +1,4 @@ -use pubgrub::{Id, Kind, State}; +use pubgrub::{Id, Kind, Ranges, State}; use rustc_hash::FxHashMap; use uv_distribution_types::{DerivationChain, DerivationStep}; @@ -37,8 +37,13 @@ impl DerivationChainBuilder { let incompat = &state.incompatibility_store[*index]; // Find a dependency from a package to the current package. - if let Kind::FromDependencyOf(id1, _, id2, v2) = &incompat.kind { - if id == *id2 && v2.contains(version) { + if let Kind::FromDependencyOf(id1, id2) = &incompat.kind { + let Some((_, dependency_versions)) = incompat.dependency_version_sets() else { + continue; + }; + let dependency_versions = + dependency_versions.cloned().unwrap_or_else(Ranges::empty); + if id == *id2 && dependency_versions.contains(version) { if let Some(version) = solution.get(id1) { let p1 = &state.package_store[*id1]; let p2 = &state.package_store[*id2]; @@ -55,7 +60,7 @@ impl DerivationChainBuilder { p1.extra().cloned(), p1.group().cloned(), Some(version.clone()), - v2.clone(), + dependency_versions, )); // Recursively search the next package. diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 873db40376c4c..94e2b52144ff1 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -2666,7 +2666,7 @@ impl ResolverState = Vec::with_capacity(edge_count); for (package, self_version) in &solution { for id in &self.pubgrub.incompatibilities[package] { - let pubgrub::Kind::FromDependencyOf( - self_package, - ref self_range, - dependency_package, - ref dependency_range, - ) = self.pubgrub.incompatibility_store[*id].kind + let incompatibility = &self.pubgrub.incompatibility_store[*id]; + let pubgrub::Kind::FromDependencyOf(self_package, dependency_package) = + &incompatibility.kind + else { + continue; + }; + let (self_package, dependency_package) = (*self_package, *dependency_package); + let Some((self_range, dependency_range)) = + incompatibility.dependency_version_sets() else { continue; }; + let dependency_range = + dependency_range.map_or_else(|| Cow::Owned(Ranges::empty()), Cow::Borrowed); if *package != self_package { continue; } @@ -4257,7 +4265,7 @@ fn find_environments(id: Id, state: &State for index in incompatibilities { let incompat = &state.incompatibility_store[*index]; - if let Kind::FromDependencyOf(parent, _, child, _) = &incompat.kind { + if let Kind::FromDependencyOf(parent, child) = &incompat.kind { if current != *child { continue; } @@ -4291,7 +4299,7 @@ fn find_environments(id: Id, state: &State for index in incompatibilities { let incompat = &state.incompatibility_store[*index]; - let Kind::FromDependencyOf(parent, _, child, _) = &incompat.kind else { + let Kind::FromDependencyOf(parent, child) = &incompat.kind else { continue; }; if current != *parent || !ancestors.contains(child) {