diff --git a/examples/unsat_root_message_no_version.rs b/examples/unsat_root_message_no_version.rs index ac258e34..5e0ac824 100644 --- a/examples/unsat_root_message_no_version.rs +++ b/examples/unsat_root_message_no_version.rs @@ -99,6 +99,13 @@ impl ReportFormatter> for CustomReportFormatter format!("{package} {package_set} depends on {dependency} {dependency_set}") } } + External::UnusableDependencies(package, set, ..) => { + if set == &Range::full() { + format!("dependencies of {package} are unusable") + } else { + format!("dependencies of {package} at version {set} are unusable") + } + } } } } diff --git a/src/internal/core.rs b/src/internal/core.rs index d29a91a5..d79ab839 100644 --- a/src/internal/core.rs +++ b/src/internal/core.rs @@ -25,7 +25,7 @@ pub struct State { root_package: DP::P, root_version: DP::V, - /// All incompatibilities indexed by package. + /// The set of incompatibilities for each package. #[allow(clippy::type_complexity)] incompatibilities: Map>>, diff --git a/src/internal/incompatibility.rs b/src/internal/incompatibility.rs index 2b3bc89f..9c05946c 100644 --- a/src/internal/incompatibility.rs +++ b/src/internal/incompatibility.rs @@ -34,14 +34,14 @@ use crate::version_set::VersionSet; #[derive(Debug, Clone)] pub struct Incompatibility { package_terms: SmallMap>, - /// The reason for the incompatibility. + /// The reason why this version or combination of versions can't be selected. pub kind: Kind, } /// Type alias of unique identifiers for incompatibilities. pub type IncompId = Id>; -/// The reason for the incompatibility. +/// The reason why a version or combination of versions can't be selected. #[derive(Debug, Clone)] pub enum Kind { /// Initial incompatibility aiming at picking the root package for the first decision. @@ -50,6 +50,8 @@ pub enum Kind { 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, Option), /// Incompatibility coming from the dependencies of a given package. FromDependencyOf(P, VS, P, VS), /// Derived from two causes. Stores cause ids. @@ -109,6 +111,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, reason: Option) -> Self { + let set = VS::singleton(version); + Self { + package_terms: SmallMap::One([(package.clone(), Term::Positive(set.clone()))]), + kind: Kind::UnusableDependencies(package, set, reason), + } + } + /// Build an incompatibility from a given dependency. pub fn from_dependency(package: P, versions: VS, dep: (&P, &VS)) -> Self { let (p2, set2) = dep; @@ -125,8 +138,7 @@ impl Incompatibility { } } - /// Return the two packages where this incompatibility when the incompatibility was created - /// through a dependency edge between the two. + /// The two packages causing the incompatibility, if it was derived from dependencies. pub fn as_dependency(&self) -> Option<(&P, &P)> { match &self.kind { Kind::FromDependencyOf(p1, _, p2, _) => Some((p1, p2)), @@ -262,6 +274,9 @@ impl Incompatibility { Kind::UnavailableDependencies(package, set) => { DerivationTree::External(External::UnavailableDependencies(package, set)) } + Kind::UnusableDependencies(package, set, reason) => { + DerivationTree::External(External::UnusableDependencies(package, set, reason)) + } Kind::FromDependencyOf(package, set, dep_package, dep_set) => DerivationTree::External( External::FromDependencyOf(package, set, dep_package, dep_set), ), diff --git a/src/report.rs b/src/report.rs index 9f354183..ecf4be78 100644 --- a/src/report.rs +++ b/src/report.rs @@ -49,6 +49,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, Option), /// Incompatibility coming from the dependencies of a given package. FromDependencyOf(P, VS, P, VS), } @@ -124,6 +126,13 @@ impl DerivationTree { DerivationTree::External(External::UnavailableDependencies(_, r)) => Some( DerivationTree::External(External::UnavailableDependencies(package, set.union(&r))), ), + DerivationTree::External(External::UnusableDependencies(_, r, reason)) => { + Some(DerivationTree::External(External::UnusableDependencies( + package, + set.union(&r), + reason, + ))) + } DerivationTree::External(External::FromDependencyOf(p1, r1, p2, r2)) => { if p1 == package { Some(DerivationTree::External(External::FromDependencyOf( @@ -169,6 +178,29 @@ impl fmt::Display for External { ) } } + Self::UnusableDependencies(package, set, reason) => { + if let Some(reason) = reason { + if set == &VS::full() { + write!(f, "dependencies of {} are unusable: {reason}", package) + } else { + write!( + f, + "dependencies of {} at version {} are unusable: {reason}", + package, set + ) + } + } else { + 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)