diff --git a/src/internal/incompatibility.rs b/src/internal/incompatibility.rs index dfcccf30..ca9e423f 100644 --- a/src/internal/incompatibility.rs +++ b/src/internal/incompatibility.rs @@ -43,28 +43,25 @@ enum Kind { /// Initial incompatibility aiming at picking the root package for the first decision. NotRoot(P, V), /// There are no versions in the given range for this package. - NoVersions(P, Range), + NoVersions(P), /// Dependencies of the package are unavailable for versions in that range. - UnavailableDependencies(P, Range), + UnavailableDependencies(P), /// Incompatibility coming from the dependencies of a given package. - FromDependencyOf(P, Range, P, Range), + FromDependencyOf(P, P), /// Derived from two causes. Stores cause ids. DerivedFrom(IncompId, IncompId), } -/// A type alias for a pair of [Package] and a corresponding [Term]. -pub type PackageTerm = (P, Term); - /// A Relation describes how a set of terms can be compared to an incompatibility. /// Typically, the set of terms comes from the partial solution. #[derive(Eq, PartialEq)] -pub enum Relation { +pub enum Relation { /// We say that a set of terms S satisfies an incompatibility I /// if S satisfies every term in I. Satisfied, /// We say that S contradicts I /// if S contradicts at least one term in I. - Contradicted(PackageTerm), + Contradicted(P), /// If S satisfies all but one of I's terms and is inconclusive for the remaining term, /// we say S "almost satisfies" I and we call the remaining term the "unsatisfied term". AlmostSatisfied(P), @@ -87,13 +84,10 @@ impl Incompatibility { /// Create an incompatibility to remember /// that a given range does not contain any version. pub fn no_versions(package: P, term: Term) -> Self { - let range = match &term { - Term::Positive(r) => r.clone(), - Term::Negative(_) => panic!("No version should have a positive term"), - }; + assert!(term.is_positive(), "No version should have a positive term"); Self { package_terms: SmallMap::One([(package.clone(), term)]), - kind: Kind::NoVersions(package, range), + kind: Kind::NoVersions(package), } } @@ -101,23 +95,24 @@ impl Incompatibility { /// that a package version is not selectable /// because its list of dependencies is unavailable. pub fn unavailable_dependencies(package: P, version: V) -> Self { - let range = Range::exact(version); Self { - package_terms: SmallMap::One([(package.clone(), Term::Positive(range.clone()))]), - kind: Kind::UnavailableDependencies(package, range), + package_terms: SmallMap::One([( + package.clone(), + Term::Positive(Range::exact(version)), + )]), + kind: Kind::UnavailableDependencies(package), } } /// Build an incompatibility from a given dependency. pub fn from_dependency(package: P, version: V, dep: (&P, &Range)) -> Self { - let range1 = Range::exact(version); let (p2, range2) = dep; Self { package_terms: SmallMap::Two([ - (package.clone(), Term::Positive(range1.clone())), + (package.clone(), Term::Positive(Range::exact(version))), (p2.clone(), Term::Negative(range2.clone())), ]), - kind: Kind::FromDependencyOf(package, range1, p2.clone(), range2.clone()), + kind: Kind::FromDependencyOf(package, p2.clone()), } } @@ -173,13 +168,13 @@ impl Incompatibility { } /// CF definition of Relation enum. - pub fn relation(&self, mut terms: impl FnMut(&P) -> Option>) -> Relation { + pub fn relation(&self, mut terms: impl FnMut(&P) -> Option>) -> Relation

{ let mut relation = Relation::Satisfied; for (package, incompat_term) in self.package_terms.iter() { match terms(package).map(|term| incompat_term.relation_with(&term)) { Some(term::Relation::Satisfied) => {} Some(term::Relation::Contradicted) => { - return Relation::Contradicted((package.clone(), incompat_term.clone())); + return Relation::Contradicted(package.clone()); } None | Some(term::Relation::Inconclusive) => { // If a package is not present, the intersection is the same as [Term::any]. @@ -242,7 +237,8 @@ impl Incompatibility { shared_ids: &Set>, store: &Arena, ) -> DerivationTree { - match &store[self_id].kind { + let val = &store[self_id]; + match &val.kind { Kind::DerivedFrom(id1, id2) => { let cause1 = Self::build_derivation_tree(*id1, shared_ids, store); let cause2 = Self::build_derivation_tree(*id2, shared_ids, store); @@ -257,18 +253,22 @@ impl Incompatibility { Kind::NotRoot(package, version) => { DerivationTree::External(External::NotRoot(package.clone(), version.clone())) } - Kind::NoVersions(package, range) => { - DerivationTree::External(External::NoVersions(package.clone(), range.clone())) + Kind::NoVersions(package) => DerivationTree::External(External::NoVersions( + package.clone(), + val.package_terms[package].as_range().clone(), + )), + Kind::UnavailableDependencies(package) => { + DerivationTree::External(External::UnavailableDependencies( + package.clone(), + val.package_terms[package].as_range().clone(), + )) } - Kind::UnavailableDependencies(package, range) => DerivationTree::External( - External::UnavailableDependencies(package.clone(), range.clone()), - ), - Kind::FromDependencyOf(package, range, dep_package, dep_range) => { + Kind::FromDependencyOf(package, dep_package) => { DerivationTree::External(External::FromDependencyOf( package.clone(), - range.clone(), + val.package_terms[package].as_range().clone(), dep_package.clone(), - dep_range.clone(), + val.package_terms[dep_package].as_range().clone(), )) } } @@ -308,12 +308,12 @@ pub mod tests { let mut store = Arena::new(); let i1 = store.alloc(Incompatibility { package_terms: SmallMap::Two([("p1", t1.clone()), ("p2", t2.negate())]), - kind: Kind::UnavailableDependencies("0", Range::any()) + kind: Kind::UnavailableDependencies("0") }); let i2 = store.alloc(Incompatibility { package_terms: SmallMap::Two([("p2", t2), ("p3", t3.clone())]), - kind: Kind::UnavailableDependencies("0", Range::any()) + kind: Kind::UnavailableDependencies("0") }); let mut i3 = Map::default(); diff --git a/src/internal/partial_solution.rs b/src/internal/partial_solution.rs index 8be4b805..2d0ecd22 100644 --- a/src/internal/partial_solution.rs +++ b/src/internal/partial_solution.rs @@ -169,7 +169,7 @@ impl PartialSolution { } /// Check if the terms in the partial solution satisfy the incompatibility. - pub fn relation(&mut self, incompat: &Incompatibility) -> Relation { + pub fn relation(&mut self, incompat: &Incompatibility) -> Relation

{ incompat.relation(|package| self.memory.term_intersection_for_package(package).cloned()) } diff --git a/src/internal/small_map.rs b/src/internal/small_map.rs index a1fe5f9e..375b4cbc 100644 --- a/src/internal/small_map.rs +++ b/src/internal/small_map.rs @@ -1,5 +1,5 @@ use crate::type_aliases::Map; -use std::hash::Hash; +use std::{hash::Hash, ops::Index}; #[derive(Debug, Clone)] pub enum SmallMap { @@ -146,6 +146,13 @@ impl SmallMap { } } +impl Index<&K> for SmallMap { + type Output = V; + fn index(&self, key: &K) -> &V { + &self.get(key).unwrap() + } +} + impl SmallMap { pub fn as_map(&self) -> Map { match self { diff --git a/src/term.rs b/src/term.rs index 63c4da7d..5bdfbdb9 100644 --- a/src/term.rs +++ b/src/term.rs @@ -71,6 +71,14 @@ impl Term { _ => panic!("Negative term cannot unwrap positive range"), } } + + /// Unwrap the range contains in the term. + pub(crate) fn as_range(&self) -> &Range { + match self { + Self::Positive(range) => range, + Self::Negative(range) => range, + } + } } /// Set operations with terms.