Skip to content

Commit

Permalink
feat!: Specify requirements in KnownDependencies with Requirement
Browse files Browse the repository at this point in the history
  • Loading branch information
eviltak committed Jul 30, 2024
1 parent bf26036 commit 0702789
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 119 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ pub struct KnownDependencies {
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub requirements: Vec<VersionSetId>,
pub requirements: Vec<Requirement>,

/// Defines additional constraints on packages that may or may not be part
/// of the solution. Different from `requirements`, packages in this set
Expand Down
40 changes: 16 additions & 24 deletions src/problem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
internal::id::{ClauseId, InternalSolvableId, SolvableId, StringId, VersionSetId},
runtime::AsyncRuntime,
solver::{clause::Clause, Solver},
DependencyProvider, Interner,
DependencyProvider, Interner, Requirement,
};

/// Represents the cause of the solver being unable to find a solution
Expand Down Expand Up @@ -198,21 +198,21 @@ impl ProblemNode {
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) enum ProblemEdge {
/// The target node is a candidate for the dependency specified by the
/// version set
Requires(VersionSetId),
/// [`Requirement`]
Requires(Requirement),
/// The target node is involved in a conflict, caused by `ConflictCause`
Conflict(ConflictCause),
}

impl ProblemEdge {
fn try_requires(self) -> Option<VersionSetId> {
fn try_requires(self) -> Option<Requirement> {
match self {
ProblemEdge::Requires(match_spec_id) => Some(match_spec_id),
ProblemEdge::Conflict(_) => None,
}
}

fn requires(self) -> VersionSetId {
fn requires(self) -> Requirement {
match self {
ProblemEdge::Requires(match_spec_id) => match_spec_id,
ProblemEdge::Conflict(_) => panic!("expected requires edge, found conflict"),
Expand Down Expand Up @@ -301,8 +301,8 @@ impl ProblemGraph {
};

let label = match edge.weight() {
ProblemEdge::Requires(version_set_id)
| ProblemEdge::Conflict(ConflictCause::Constrains(version_set_id)) => {
ProblemEdge::Requires(requirement) => requirement.display(interner).to_string(),
ProblemEdge::Conflict(ConflictCause::Constrains(version_set_id)) => {
interner.display_version_set(*version_set_id).to_string()
}
ProblemEdge::Conflict(ConflictCause::ForbidMultipleInstances)
Expand Down Expand Up @@ -651,7 +651,7 @@ impl<'i, I: Interner> DisplayUnsat<'i, I> {
top_level_indent: bool,
) -> fmt::Result {
pub enum DisplayOp {
Requirement(VersionSetId, Vec<EdgeIndex>),
Requirement(Requirement, Vec<EdgeIndex>),
Candidate(NodeIndex),
}

Expand Down Expand Up @@ -693,43 +693,35 @@ impl<'i, I: Interner> DisplayUnsat<'i, I> {
let indent = indenter.get_indent();

match node {
DisplayOp::Requirement(version_set_id, edges) => {
DisplayOp::Requirement(requirement, edges) => {
debug_assert!(!edges.is_empty());

let installable = edges.iter().any(|&e| {
let (_, target) = graph.edge_endpoints(e).unwrap();
installable_nodes.contains(&target)
});

let req = self
.interner
.display_version_set(version_set_id)
.to_string();
let name = self.interner.version_set_name(version_set_id);
let name = self.interner.display_name(name).to_string();
let req = requirement.display(self.interner).to_string();

let target_nx = graph.edge_endpoints(edges[0]).unwrap().1;
let missing =
edges.len() == 1 && graph[target_nx] == ProblemNode::UnresolvedDependency;
if missing {
// No candidates for requirement
if top_level {
writeln!(f, "{indent}No candidates were found for {name} {req}.")?;
writeln!(f, "{indent}No candidates were found for {req}.")?;
} else {
writeln!(
f,
"{indent}{name} {req}, for which no candidates were found.",
)?;
writeln!(f, "{indent}{req}, for which no candidates were found.",)?;
}
} else if installable {
// Package can be installed (only mentioned for top-level requirements)
if top_level {
writeln!(
f,
"{indent}{name} {req} can be installed with any of the following options:"
"{indent}{req} can be installed with any of the following options:"
)?;
} else {
writeln!(f, "{indent}{name} {req}, which can be installed with any of the following options:")?;
writeln!(f, "{indent}{req}, which can be installed with any of the following options:")?;
}

let children: Vec<_> = edges
Expand Down Expand Up @@ -780,9 +772,9 @@ impl<'i, I: Interner> DisplayUnsat<'i, I> {
// Package cannot be installed (the conflicting requirement is further down
// the tree)
if top_level {
writeln!(f, "{indent}{name} {req} cannot be installed because there are no viable options:")?;
writeln!(f, "{indent}{req} cannot be installed because there are no viable options:")?;
} else {
writeln!(f, "{indent}{name} {req}, which cannot be installed because there are no viable options:")?;
writeln!(f, "{indent}{req}, which cannot be installed because there are no viable options:")?;
}

let children: Vec<_> = edges
Expand Down
61 changes: 50 additions & 11 deletions src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use futures::FutureExt;

use crate::{
internal::arena::ArenaId, Candidates, Dependencies, DependencyProvider, Interner, Mapping,
NameId, SolvableId, SolverCache, StringId, VersionSetId, VersionSetUnionId,
NameId, Requirement, SolvableId, SolverCache, StringId, VersionSetId, VersionSetUnionId,
};

/// A single solvable in a [`DependencySnapshot`].
Expand Down Expand Up @@ -84,12 +84,19 @@ pub struct DependencySnapshot {
)]
pub solvables: Mapping<SolvableId, Solvable>,

/// All the requirements in the snapshot
/// All the version set unions in the snapshot
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Mapping::is_empty")
)]
pub requirements: Mapping<VersionSetId, VersionSet>,
pub version_set_unions: Mapping<VersionSetUnionId, HashSet<VersionSetId>>,

/// All the version sets in the snapshot
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Mapping::is_empty")
)]
pub version_sets: Mapping<VersionSetId, VersionSet>,

/// All the packages in the snapshot
#[cfg_attr(
Expand Down Expand Up @@ -151,7 +158,8 @@ impl DependencySnapshot {

let mut result = Self {
solvables: Mapping::new(),
requirements: Mapping::new(),
version_set_unions: Mapping::new(),
version_sets: Mapping::new(),
packages: Mapping::new(),
strings: Mapping::new(),
};
Expand Down Expand Up @@ -206,11 +214,37 @@ impl DependencySnapshot {
}
}
Dependencies::Known(deps) => {
for &dep in deps.requirements.iter().chain(deps.constrains.iter()) {
for &dep in deps.constrains.iter() {
if seen.insert(Element::VersionSet(dep)) {
queue.push_back(Element::VersionSet(dep));
}
}

for &requirement in deps.requirements.iter() {
match requirement {
Requirement::Single(version_set) => {
if seen.insert(Element::VersionSet(version_set)) {
queue.push_back(Element::VersionSet(version_set));
}
}
Requirement::Union(version_set_union_id) => {
let version_sets: HashSet<_> = cache
.provider()
.version_sets_in_union(version_set_union_id)
.collect();

for &version_set in version_sets.iter() {
if seen.insert(Element::VersionSet(version_set)) {
queue.push_back(Element::VersionSet(version_set));
}
}

result
.version_set_unions
.insert(version_set_union_id, version_sets);
}
}
}
}
}

Expand Down Expand Up @@ -255,7 +289,7 @@ impl DependencySnapshot {
matching_candidates: matching_candidates.iter().copied().collect(),
};

result.requirements.insert(version_set_id, version_set);
result.version_sets.insert(version_set_id, version_set);
}
}
}
Expand Down Expand Up @@ -323,7 +357,7 @@ impl<'s> SnapshotProvider<'s> {

/// Adds another requirement that matches any version of a package
pub fn add_package_requirement(&mut self, name: NameId) -> VersionSetId {
let id = self.snapshot.requirements.max() + self.additional_version_sets.len();
let id = self.snapshot.version_sets.max() + self.additional_version_sets.len();

let package = self.package(name);

Expand Down Expand Up @@ -360,12 +394,12 @@ impl<'s> SnapshotProvider<'s> {

fn version_set(&self, version_set: VersionSetId) -> &VersionSet {
let idx = version_set.to_usize();
let max_idx = self.snapshot.requirements.max();
let max_idx = self.snapshot.version_sets.max();
if idx >= max_idx {
&self.additional_version_sets[idx - max_idx]
} else {
self.snapshot
.requirements
.version_sets
.get(version_set)
.expect("missing version set")
}
Expand Down Expand Up @@ -399,9 +433,14 @@ impl<'s> Interner for SnapshotProvider<'s> {

fn version_sets_in_union(
&self,
_version_set_union: VersionSetUnionId,
version_set_union_id: VersionSetUnionId,
) -> impl Iterator<Item = VersionSetId> {
std::iter::empty()
self.snapshot
.version_set_unions
.get(version_set_union_id)
.expect("missing constraint")
.iter()
.copied()
}
}

Expand Down
Loading

0 comments on commit 0702789

Please sign in to comment.