diff --git a/Cargo.lock b/Cargo.lock index 70a0eb49235e..ea352fe825ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2479,7 +2479,7 @@ dependencies = [ [[package]] name = "pubgrub" version = "0.2.1" -source = "git+https://github.com/astral-sh/pubgrub?rev=19c77268c0ad5f69d7e12126e0cfacfbba466481#19c77268c0ad5f69d7e12126e0cfacfbba466481" +source = "git+https://github.com/astral-sh/pubgrub?rev=7243f4faf8e54837aa8a401a18406e7173de4ad5#7243f4faf8e54837aa8a401a18406e7173de4ad5" dependencies = [ "indexmap", "log", diff --git a/Cargo.toml b/Cargo.toml index 3046f7f8e1e1..42d211889059 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,7 +125,7 @@ pathdiff = { version = "0.2.1" } petgraph = { version = "0.6.5" } platform-info = { version = "2.0.3" } proc-macro2 = { version = "1.0.86" } -pubgrub = { git = "https://github.com/astral-sh/pubgrub", rev = "19c77268c0ad5f69d7e12126e0cfacfbba466481" } +pubgrub = { git = "https://github.com/astral-sh/pubgrub", rev = "7243f4faf8e54837aa8a401a18406e7173de4ad5" } quote = { version = "1.0.37" } rayon = { version = "1.10.0" } reflink-copy = { version = "0.1.19" } diff --git a/crates/uv-resolver/src/resolver/batch_prefetch.rs b/crates/uv-resolver/src/resolver/batch_prefetch.rs index 586a5e3befba..98fe2d5e2421 100644 --- a/crates/uv-resolver/src/resolver/batch_prefetch.rs +++ b/crates/uv-resolver/src/resolver/batch_prefetch.rs @@ -1,7 +1,7 @@ use std::cmp::min; use itertools::Itertools; -use pubgrub::Range; +use pubgrub::{Range, Term}; use rustc_hash::FxHashMap; use tokio::sync::mpsc::Sender; use tracing::{debug, trace}; @@ -49,6 +49,7 @@ impl BatchPrefetcher { index: Option<&IndexUrl>, version: &Version, current_range: &Range, + unchangeable_constraints: Option<&Term>>, python_requirement: &PythonRequirement, request_sink: &Sender, in_memory: &InMemoryIndex, @@ -119,11 +120,22 @@ impl BatchPrefetcher { } } BatchPrefetchStrategy::InOrder { previous } => { - let range = if selector.use_highest_version(name) { + let mut range = if selector.use_highest_version(name) { Range::strictly_lower_than(previous) } else { Range::strictly_higher_than(previous) }; + // If we have constraints from root, don't go beyond those. Example: We are + // prefetching for foo 1.60 and have a dependency for `foo>=1.50`, so we should + // only prefetch 1.60 to 1.50, knowing 1.49 will always be rejected. + if let Some(unchangeable_constraints) = unchangeable_constraints { + range = match unchangeable_constraints { + Term::Positive(constraints) => range.intersection(constraints), + Term::Negative(negative_constraints) => { + range.intersection(&negative_constraints.complement()) + } + }; + } if let Some(candidate) = selector.select_no_preference(name, &range, version_map, markers) { diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 4570a5e81e3f..279864f4a04a 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -477,6 +477,10 @@ impl ResolverState