Skip to content

Commit 70a3ccb

Browse files
committed
Display dep requirement info for cyclic dependencies
1 parent 7d22a30 commit 70a3ccb

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

src/cargo/core/resolver/mod.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
//! that we're implementing something that probably shouldn't be allocating all
4848
//! over the place.
4949
50-
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
50+
use std::collections::{BTreeMap, HashMap, HashSet};
5151
use std::mem;
5252
use std::rc::Rc;
5353
use std::time::{Duration, Instant};
@@ -1007,13 +1007,15 @@ fn check_cycles(resolve: &Resolve) -> CargoResult<()> {
10071007
// dev-dependency since that doesn't count for cycles.
10081008
let mut graph = BTreeMap::new();
10091009
for id in resolve.iter() {
1010-
let set = graph.entry(id).or_insert_with(BTreeSet::new);
1011-
for (dep, listings) in resolve.deps_not_replaced(id) {
1012-
let is_transitive = listings.iter().any(|d| d.is_transitive());
1013-
1014-
if is_transitive {
1015-
set.insert(dep);
1016-
set.extend(resolve.replacement(dep));
1010+
let map = graph.entry(id).or_insert_with(BTreeMap::new);
1011+
for (dep_id, listings) in resolve.deps_not_replaced(id) {
1012+
let transitive_dep = listings.iter().find(|d| d.is_transitive());
1013+
1014+
if let Some(transitive_dep) = transitive_dep.cloned() {
1015+
map.insert(dep_id, transitive_dep.clone());
1016+
resolve
1017+
.replacement(dep_id)
1018+
.map(|p| map.insert(p, transitive_dep));
10171019
}
10181020
}
10191021
}
@@ -1033,23 +1035,29 @@ fn check_cycles(resolve: &Resolve) -> CargoResult<()> {
10331035
return Ok(());
10341036

10351037
fn visit(
1036-
graph: &BTreeMap<PackageId, BTreeSet<PackageId>>,
1038+
graph: &BTreeMap<PackageId, BTreeMap<PackageId, Dependency>>,
10371039
id: PackageId,
10381040
visited: &mut HashSet<PackageId>,
10391041
path: &mut Vec<PackageId>,
10401042
checked: &mut HashSet<PackageId>,
10411043
) -> CargoResult<()> {
10421044
path.push(id);
10431045
if !visited.insert(id) {
1046+
let iter = path.iter().rev().skip(1).scan(id, |child, parent| {
1047+
let dep = graph.get(parent).and_then(|adjacent| adjacent.get(child));
1048+
*child = *parent;
1049+
Some((parent, dep))
1050+
});
1051+
let iter = std::iter::once((&id, None)).chain(iter);
10441052
anyhow::bail!(
10451053
"cyclic package dependency: package `{}` depends on itself. Cycle:\n{}",
10461054
id,
1047-
errors::describe_path(&path.iter().rev().collect::<Vec<_>>()),
1055+
errors::describe_path(iter),
10481056
);
10491057
}
10501058

10511059
if checked.insert(id) {
1052-
for dep in graph[&id].iter() {
1060+
for dep in graph[&id].keys() {
10531061
visit(graph, *dep, visited, path, checked)?;
10541062
}
10551063
}

0 commit comments

Comments
 (0)