Skip to content

Commit da56fa5

Browse files
authored
fix: merge similar excluded messages when unsat (#26)
1 parent 0469394 commit da56fa5

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

src/problem.rs

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ impl Problem {
4747
) -> ProblemGraph {
4848
let mut graph = DiGraph::<ProblemNode, ProblemEdge>::default();
4949
let mut nodes: HashMap<SolvableId, NodeIndex> = HashMap::default();
50+
let mut excluded_nodes: HashMap<StringId, NodeIndex> = HashMap::default();
5051

5152
let root_node = Self::add_node(&mut graph, &mut nodes, SolvableId::root());
5253
let unresolved_node = graph.add_node(ProblemNode::UnresolvedDependency);
@@ -58,8 +59,15 @@ impl Problem {
5859
Clause::Excluded(solvable, reason) => {
5960
tracing::info!("{solvable:?} is excluded");
6061
let package_node = Self::add_node(&mut graph, &mut nodes, *solvable);
61-
let conflict = ConflictCause::Excluded(*solvable, *reason);
62-
graph.add_edge(root_node, package_node, ProblemEdge::Conflict(conflict));
62+
let excluded_node = excluded_nodes
63+
.entry(*reason)
64+
.or_insert_with(|| graph.add_node(ProblemNode::Excluded(*reason)));
65+
66+
graph.add_edge(
67+
package_node,
68+
*excluded_node,
69+
ProblemEdge::Conflict(ConflictCause::Excluded),
70+
);
6371
}
6472
Clause::Learnt(..) => unreachable!(),
6573
&Clause::Requires(package_id, version_set_id) => {
@@ -176,6 +184,8 @@ pub enum ProblemNode {
176184
Solvable(SolvableId),
177185
/// Node representing a dependency without candidates
178186
UnresolvedDependency,
187+
/// Node representing an exclude reason
188+
Excluded(StringId),
179189
}
180190

181191
impl ProblemNode {
@@ -185,6 +195,9 @@ impl ProblemNode {
185195
ProblemNode::UnresolvedDependency => {
186196
panic!("expected solvable node, found unresolved dependency")
187197
}
198+
ProblemNode::Excluded(_) => {
199+
panic!("expected solvable node, found excluded node")
200+
}
188201
}
189202
}
190203
}
@@ -224,7 +237,7 @@ pub enum ConflictCause {
224237
/// It is forbidden to install multiple instances of the same dependency
225238
ForbidMultipleInstances,
226239
/// The node was excluded
227-
Excluded(SolvableId, StringId),
240+
Excluded,
228241
}
229242

230243
/// Represents a node that has been merged with others
@@ -302,9 +315,7 @@ impl ProblemGraph {
302315
| ProblemEdge::Conflict(ConflictCause::Locked(_)) => {
303316
"already installed".to_string()
304317
}
305-
ProblemEdge::Conflict(ConflictCause::Excluded(_, reason)) => {
306-
format!("excluded because {}", pool.resolve_string(*reason))
307-
}
318+
ProblemEdge::Conflict(ConflictCause::Excluded) => "excluded".to_string(),
308319
};
309320

310321
let target = match target {
@@ -322,6 +333,9 @@ impl ProblemGraph {
322333
solvable_2.display(pool).to_string()
323334
}
324335
ProblemNode::UnresolvedDependency => "unresolved".to_string(),
336+
ProblemNode::Excluded(reason) => {
337+
format!("reason: {}", pool.resolve_string(reason))
338+
}
325339
};
326340

327341
write!(
@@ -346,7 +360,7 @@ impl ProblemGraph {
346360
let mut maybe_merge = HashMap::new();
347361
for node_id in graph.node_indices() {
348362
let candidate = match graph[node_id] {
349-
ProblemNode::UnresolvedDependency => continue,
363+
ProblemNode::UnresolvedDependency | ProblemNode::Excluded(_) => continue,
350364
ProblemNode::Solvable(solvable_id) => {
351365
if solvable_id.is_root() {
352366
continue;
@@ -415,12 +429,10 @@ impl ProblemGraph {
415429

416430
// Determine any incoming "exclude" edges to the node. This would indicate that the
417431
// node is disabled for external reasons.
418-
let excluding_edges = self.graph.edges_directed(nx, Direction::Incoming).any(|e| {
419-
matches!(
420-
e.weight(),
421-
ProblemEdge::Conflict(ConflictCause::Excluded(_, _))
422-
)
423-
});
432+
let excluding_edges = self
433+
.graph
434+
.edges_directed(nx, Direction::Incoming)
435+
.any(|e| matches!(e.weight(), ProblemEdge::Conflict(ConflictCause::Excluded)));
424436
if excluding_edges {
425437
// Nodes with incoming disabling edges aren't installable
426438
continue;
@@ -673,9 +685,12 @@ impl<'pool, VS: VersionSet, N: PackageName + Display, M: SolvableDisplay<VS, N>>
673685
};
674686

675687
let excluded = graph
676-
.edges_directed(candidate, Direction::Incoming)
688+
.edges_directed(candidate, Direction::Outgoing)
677689
.find_map(|e| match e.weight() {
678-
ProblemEdge::Conflict(ConflictCause::Excluded(_, reason)) => {
690+
ProblemEdge::Conflict(ConflictCause::Excluded) => {
691+
let ProblemNode::Excluded(reason) = graph[e.target()] else {
692+
unreachable!();
693+
};
679694
Some(reason)
680695
}
681696
_ => None,
@@ -695,7 +710,7 @@ impl<'pool, VS: VersionSet, N: PackageName + Display, M: SolvableDisplay<VS, N>>
695710
writeln!(
696711
f,
697712
"{indent}{name} {version} is excluded because {reason}",
698-
reason = self.pool.resolve_string(*excluded_reason)
713+
reason = self.pool.resolve_string(excluded_reason)
699714
)?;
700715
} else if is_leaf {
701716
writeln!(f, "{indent}{name} {version}")?;
@@ -795,7 +810,7 @@ impl<VS: VersionSet, N: PackageName + Display, M: SolvableDisplay<VS, N>> fmt::D
795810
.display_candidates(self.pool, &[solvable_id])
796811
)?;
797812
}
798-
ConflictCause::Excluded(_, _) => continue,
813+
ConflictCause::Excluded => continue,
799814
};
800815
}
801816
}

tests/snapshots/solver__merge_excluded.snap

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ expression: "solve_snapshot(provider, &[\"a\"])"
44
---
55
The following packages are incompatible
66
|-- a * cannot be installed because there are no viable options:
7-
|-- a 2 is excluded because it is externally excluded
8-
|-- a 1 is excluded because it is externally excluded
7+
|-- a 1 | 2 is excluded because it is externally excluded
98

0 commit comments

Comments
 (0)