diff --git a/examples/caching_dependency_provider.rs b/examples/caching_dependency_provider.rs index 6ef8e893..a12bea92 100644 --- a/examples/caching_dependency_provider.rs +++ b/examples/caching_dependency_provider.rs @@ -52,6 +52,7 @@ impl> DependencyProvid Ok(Dependencies::Known(dependencies)) } Ok(Dependencies::Unknown) => Ok(Dependencies::Unknown), + Ok(Dependencies::Unusable) => Ok(Dependencies::Unusable), error @ Err(_) => error, } } diff --git a/src/internal/incompatibility.rs b/src/internal/incompatibility.rs index b56a3c44..f46e2bdd 100644 --- a/src/internal/incompatibility.rs +++ b/src/internal/incompatibility.rs @@ -31,20 +31,22 @@ use crate::version_set::VersionSet; #[derive(Debug, Clone)] pub struct Incompatibility { package_terms: SmallMap>, - kind: Kind, + pub kind: Kind, } /// Type alias of unique identifiers for incompatibilities. pub type IncompId = Id>; #[derive(Debug, Clone)] -enum Kind { +pub enum Kind { /// Initial incompatibility aiming at picking the root package for the first decision. NotRoot(P, VS::V), /// There are no versions in the given range for this package. NoVersions(P, VS), /// Dependencies of the package are unavailable for versions in that range. UnavailableDependencies(P, VS), + /// Dependencies of the package are unusable for versions in that range. + UnusableDependencies(P, VS), /// Incompatibility coming from the dependencies of a given package. FromDependencyOf(P, VS, P, VS), /// Derived from two causes. Stores cause ids. @@ -104,6 +106,17 @@ impl Incompatibility { } } + /// Create an incompatibility to remember + /// that a package version is not selectable + /// because its dependencies are not usable. + pub fn unusable_dependencies(package: P, version: VS::V) -> Self { + let set = VS::singleton(version); + Self { + package_terms: SmallMap::One([(package.clone(), Term::Positive(set.clone()))]), + kind: Kind::UnusableDependencies(package, set), + } + } + /// Build an incompatibility from a given dependency. pub fn from_dependency(package: P, version: VS::V, dep: (&P, &VS)) -> Self { let set1 = VS::singleton(version); @@ -206,6 +219,9 @@ impl Incompatibility { Kind::UnavailableDependencies(package, set) => DerivationTree::External( External::UnavailableDependencies(package.clone(), set.clone()), ), + Kind::UnusableDependencies(package, set) => DerivationTree::External( + External::UnusableDependencies(package.clone(), set.clone()), + ), Kind::FromDependencyOf(package, set, dep_package, dep_set) => { DerivationTree::External(External::FromDependencyOf( package.clone(), diff --git a/src/report.rs b/src/report.rs index ff0b2d3f..a1945d46 100644 --- a/src/report.rs +++ b/src/report.rs @@ -41,6 +41,8 @@ pub enum External { NoVersions(P, VS), /// Dependencies of the package are unavailable for versions in that set. UnavailableDependencies(P, VS), + /// Dependencies of the package are unusable for versions in that set. + UnusableDependencies(P, VS), /// Incompatibility coming from the dependencies of a given package. FromDependencyOf(P, VS, P, VS), } @@ -113,6 +115,9 @@ impl DerivationTree { DerivationTree::External(External::UnavailableDependencies(_, r)) => Some( DerivationTree::External(External::UnavailableDependencies(package, set.union(&r))), ), + DerivationTree::External(External::UnusableDependencies(_, r)) => Some( + DerivationTree::External(External::UnusableDependencies(package, set.union(&r))), + ), DerivationTree::External(External::FromDependencyOf(p1, r1, p2, r2)) => { if p1 == package { Some(DerivationTree::External(External::FromDependencyOf( @@ -158,6 +163,17 @@ impl fmt::Display for External { ) } } + Self::UnusableDependencies(package, set) => { + if set == &VS::full() { + write!(f, "dependencies of {} are unusable", package) + } else { + write!( + f, + "dependencies of {} at version {} are unusable", + package, set + ) + } + } Self::FromDependencyOf(p, set_p, dep, set_dep) => { if set_p == &VS::full() && set_dep == &VS::full() { write!(f, "{} depends on {}", p, dep) diff --git a/src/solver.rs b/src/solver.rs index a1e5e06c..76c26c7d 100644 --- a/src/solver.rs +++ b/src/solver.rs @@ -162,6 +162,13 @@ pub fn resolve( )); continue; } + Dependencies::Unusable => { + state.add_incompatibility(Incompatibility::unusable_dependencies( + p.clone(), + v.clone(), + )); + continue; + } Dependencies::Known(x) if x.contains_key(p) => { return Err(PubGrubError::SelfDependency { package: p.clone(), @@ -199,6 +206,8 @@ pub fn resolve( pub enum Dependencies { /// Package dependencies are unavailable. Unknown, + /// Package dependencies are unusable. + Unusable, /// Container for all available package versions. Known(DependencyConstraints), } diff --git a/tests/proptest.rs b/tests/proptest.rs index 017efed0..88f9aef4 100644 --- a/tests/proptest.rs +++ b/tests/proptest.rs @@ -316,6 +316,7 @@ fn retain_versions( } let deps = match dependency_provider.get_dependencies(&n, &v).unwrap() { Dependencies::Unknown => panic!(), + Dependencies::Unusable => panic!(), Dependencies::Known(deps) => deps, }; smaller_dependency_provider.add_dependencies(n.clone(), v.clone(), deps) @@ -340,6 +341,7 @@ fn retain_dependencies( for v in dependency_provider.versions(n).unwrap() { let deps = match dependency_provider.get_dependencies(&n, &v).unwrap() { Dependencies::Unknown => panic!(), + Dependencies::Unusable => panic!(), Dependencies::Known(deps) => deps, }; smaller_dependency_provider.add_dependencies( @@ -511,6 +513,7 @@ proptest! { .unwrap() { Dependencies::Unknown => panic!(), + Dependencies::Unusable => panic!(), Dependencies::Known(d) => d.into_iter().collect(), }; if !dependencies.is_empty() { diff --git a/tests/sat_dependency_provider.rs b/tests/sat_dependency_provider.rs index 2bfb21e9..bf7627f4 100644 --- a/tests/sat_dependency_provider.rs +++ b/tests/sat_dependency_provider.rs @@ -67,6 +67,7 @@ impl SatResolve { for (p, v, var) in &all_versions { let deps = match dp.get_dependencies(p, v).unwrap() { Dependencies::Unknown => panic!(), + Dependencies::Unusable => panic!(), Dependencies::Known(d) => d, }; for (p1, range) in &deps {