Skip to content

Commit 8c4c380

Browse files
committed
maintain a graph of parents so we can quickly walk to the root
1 parent 363105f commit 8c4c380

File tree

5 files changed

+62
-30
lines changed

5 files changed

+62
-30
lines changed

src/cargo/core/resolver/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ pub struct Context {
2828
pub resolve_features: im_rc::HashMap<PackageId, Rc<HashSet<InternedString>>>,
2929
pub links: im_rc::HashMap<InternedString, PackageId>,
3030

31+
// This is somewhat redundant with the `resolve_graph` that stores the same data,
32+
// but for querying in the opposite order.
33+
pub parents: Graph<PackageId, Rc<Vec<Dependency>>>,
34+
3135
// These are two cheaply-cloneable lists (O(1) clone) which are effectively
3236
// hash maps but are built up as "construction lists". We'll iterate these
3337
// at the very end and actually construct the map that we're making.
@@ -46,6 +50,7 @@ impl Context {
4650
resolve_graph: RcList::new(),
4751
resolve_features: im_rc::HashMap::new(),
4852
links: im_rc::HashMap::new(),
53+
parents: Graph::new(),
4954
resolve_replacements: RcList::new(),
5055
activations: im_rc::HashMap::new(),
5156
warnings: RcList::new(),

src/cargo/core/resolver/errors.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,11 @@ pub(super) fn activation_error(
7777
candidates: &[Candidate],
7878
config: Option<&Config>,
7979
) -> ResolveError {
80-
let graph = cx.graph();
8180
let to_resolve_err = |err| {
8281
ResolveError::new(
8382
err,
84-
graph
85-
.path_to_top(&parent.package_id())
83+
cx.parents
84+
.path_to_bottom(&parent.package_id())
8685
.into_iter()
8786
.cloned()
8887
.collect(),
@@ -92,7 +91,9 @@ pub(super) fn activation_error(
9291
if !candidates.is_empty() {
9392
let mut msg = format!("failed to select a version for `{}`.", dep.package_name());
9493
msg.push_str("\n ... required by ");
95-
msg.push_str(&describe_path(&graph.path_to_top(&parent.package_id())));
94+
msg.push_str(&describe_path(
95+
&cx.parents.path_to_bottom(&parent.package_id()),
96+
));
9697

9798
msg.push_str("\nversions that meet the requirements `");
9899
msg.push_str(&dep.version_req().to_string());
@@ -123,7 +124,7 @@ pub(super) fn activation_error(
123124
msg.push_str(link);
124125
msg.push_str("` as well:\n");
125126
}
126-
msg.push_str(&describe_path(&graph.path_to_top(p)));
127+
msg.push_str(&describe_path(&cx.parents.path_to_bottom(p)));
127128
}
128129

129130
let (features_errors, other_errors): (Vec<_>, Vec<_>) = other_errors
@@ -154,7 +155,7 @@ pub(super) fn activation_error(
154155

155156
for &(p, _) in other_errors.iter() {
156157
msg.push_str("\n\n previously selected ");
157-
msg.push_str(&describe_path(&graph.path_to_top(p)));
158+
msg.push_str(&describe_path(&cx.parents.path_to_bottom(p)));
158159
}
159160

160161
msg.push_str("\n\nfailed to select a version for `");
@@ -204,7 +205,9 @@ pub(super) fn activation_error(
204205
registry.describe_source(dep.source_id()),
205206
);
206207
msg.push_str("required by ");
207-
msg.push_str(&describe_path(&graph.path_to_top(&parent.package_id())));
208+
msg.push_str(&describe_path(
209+
&cx.parents.path_to_bottom(&parent.package_id()),
210+
));
208211

209212
// If we have a path dependency with a locked version, then this may
210213
// indicate that we updated a sub-package and forgot to run `cargo
@@ -265,7 +268,9 @@ pub(super) fn activation_error(
265268
msg.push_str("\n");
266269
}
267270
msg.push_str("required by ");
268-
msg.push_str(&describe_path(&graph.path_to_top(&parent.package_id())));
271+
msg.push_str(&describe_path(
272+
&cx.parents.path_to_bottom(&parent.package_id()),
273+
));
269274

270275
msg
271276
};

src/cargo/core/resolver/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,11 @@ fn activate(
591591
candidate.summary.package_id(),
592592
dep.clone(),
593593
));
594+
Rc::make_mut(
595+
cx.parents
596+
.link(candidate.summary.package_id(), parent.package_id()),
597+
)
598+
.push(dep.clone());
594599
}
595600

596601
let activated = cx.flag_activated(&candidate.summary, method)?;

src/cargo/core/resolver/resolve.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::borrow::Borrow;
22
use std::collections::{HashMap, HashSet};
33
use std::fmt;
4-
use std::hash::Hash;
54
use std::iter::FromIterator;
65

76
use url::Url;
@@ -163,7 +162,7 @@ unable to verify that `{0}` is the same as when the lockfile was generated
163162
pub fn contains<Q: ?Sized>(&self, k: &Q) -> bool
164163
where
165164
PackageId: Borrow<Q>,
166-
Q: Hash + Eq,
165+
Q: Ord + Eq,
167166
{
168167
self.graph.contains(k)
169168
}
@@ -179,11 +178,11 @@ unable to verify that `{0}` is the same as when the lockfile was generated
179178
pub fn deps(&self, pkg: PackageId) -> impl Iterator<Item = (PackageId, &[Dependency])> {
180179
self.graph
181180
.edges(&pkg)
182-
.map(move |(&id, deps)| (self.replacement(id).unwrap_or(id), deps.as_slice()))
181+
.map(move |&(id, ref deps)| (self.replacement(id).unwrap_or(id), deps.as_slice()))
183182
}
184183

185184
pub fn deps_not_replaced<'a>(&'a self, pkg: PackageId) -> impl Iterator<Item = PackageId> + 'a {
186-
self.graph.edges(&pkg).map(|(&id, _)| id)
185+
self.graph.edges(&pkg).map(|&(id, _)| id)
187186
}
188187

189188
pub fn replacement(&self, pkg: PackageId) -> Option<PackageId> {

src/cargo/util/graph.rs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
11
use std::borrow::Borrow;
2-
use std::collections::{HashMap, HashSet};
2+
use std::collections::BTreeSet;
33
use std::fmt;
4-
use std::hash::Hash;
54

6-
pub struct Graph<N, E> {
7-
nodes: HashMap<N, HashMap<N, E>>,
5+
use im_rc;
6+
7+
pub struct Graph<N: Clone, E: Clone> {
8+
nodes: im_rc::OrdMap<N, im_rc::OrdMap<N, E>>,
89
}
910

10-
impl<N: Eq + Hash + Clone, E: Default> Graph<N, E> {
11+
impl<N: Eq + Ord + Clone, E: Default + Clone> Graph<N, E> {
1112
pub fn new() -> Graph<N, E> {
1213
Graph {
13-
nodes: HashMap::new(),
14+
nodes: im_rc::OrdMap::new(),
1415
}
1516
}
1617

1718
pub fn add(&mut self, node: N) {
18-
self.nodes.entry(node).or_insert_with(HashMap::new);
19+
self.nodes.entry(node).or_insert_with(im_rc::OrdMap::new);
1920
}
2021

2122
pub fn link(&mut self, node: N, child: N) -> &mut E {
2223
self.nodes
2324
.entry(node)
24-
.or_insert_with(HashMap::new)
25+
.or_insert_with(im_rc::OrdMap::new)
2526
.entry(child)
2627
.or_insert_with(Default::default)
2728
}
2829

2930
pub fn contains<Q: ?Sized>(&self, k: &Q) -> bool
3031
where
3132
N: Borrow<Q>,
32-
Q: Hash + Eq,
33+
Q: Ord + Eq,
3334
{
3435
self.nodes.contains_key(k)
3536
}
@@ -38,14 +39,14 @@ impl<N: Eq + Hash + Clone, E: Default> Graph<N, E> {
3839
self.nodes.get(from)?.get(to)
3940
}
4041

41-
pub fn edges(&self, from: &N) -> impl Iterator<Item = (&N, &E)> {
42+
pub fn edges(&self, from: &N) -> impl Iterator<Item = &(N, E)> {
4243
self.nodes.get(from).into_iter().flat_map(|x| x.iter())
4344
}
4445

4546
/// A topological sort of the `Graph`
4647
pub fn sort(&self) -> Vec<N> {
4748
let mut ret = Vec::new();
48-
let mut marks = HashSet::new();
49+
let mut marks = BTreeSet::new();
4950

5051
for node in self.nodes.keys() {
5152
self.sort_inner_visit(node, &mut ret, &mut marks);
@@ -54,7 +55,7 @@ impl<N: Eq + Hash + Clone, E: Default> Graph<N, E> {
5455
ret
5556
}
5657

57-
fn sort_inner_visit(&self, node: &N, dst: &mut Vec<N>, marks: &mut HashSet<N>) {
58+
fn sort_inner_visit(&self, node: &N, dst: &mut Vec<N>, marks: &mut BTreeSet<N>) {
5859
if !marks.insert(node.clone()) {
5960
return;
6061
}
@@ -70,6 +71,23 @@ impl<N: Eq + Hash + Clone, E: Default> Graph<N, E> {
7071
self.nodes.keys()
7172
}
7273

74+
/// Resolves one of the paths from the given dependent package down to
75+
/// a leaf.
76+
pub fn path_to_bottom<'a>(&'a self, mut pkg: &'a N) -> Vec<&'a N> {
77+
let mut result = vec![pkg];
78+
while let Some(p) = self.nodes.get(pkg).and_then(|p| {
79+
p.iter()
80+
// Note that we can have "cycles" introduced through dev-dependency
81+
// edges, so make sure we don't loop infinitely.
82+
.find(|&(node, _)| !result.contains(&node))
83+
.map(|(ref p, _)| p)
84+
}) {
85+
result.push(p);
86+
pkg = p;
87+
}
88+
result
89+
}
90+
7391
/// Resolves one of the paths from the given dependent package up to
7492
/// the root.
7593
pub fn path_to_top<'a>(&'a self, mut pkg: &'a N) -> Vec<&'a N> {
@@ -84,7 +102,7 @@ impl<N: Eq + Hash + Clone, E: Default> Graph<N, E> {
84102
// Note that we can have "cycles" introduced through dev-dependency
85103
// edges, so make sure we don't loop infinitely.
86104
.find(|&(node, _)| !res.contains(&node))
87-
.map(|p| p.0)
105+
.map(|(ref p, _)| p)
88106
};
89107
while let Some(p) = first_pkg_depending_on(pkg, &result) {
90108
result.push(p);
@@ -94,13 +112,13 @@ impl<N: Eq + Hash + Clone, E: Default> Graph<N, E> {
94112
}
95113
}
96114

97-
impl<N: Eq + Hash + Clone, E: Default> Default for Graph<N, E> {
115+
impl<N: Eq + Ord + Clone, E: Default + Clone> Default for Graph<N, E> {
98116
fn default() -> Graph<N, E> {
99117
Graph::new()
100118
}
101119
}
102120

103-
impl<N: fmt::Display + Eq + Hash, E> fmt::Debug for Graph<N, E> {
121+
impl<N: fmt::Display + Eq + Ord + Clone, E: Clone> fmt::Debug for Graph<N, E> {
104122
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
105123
writeln!(fmt, "Graph {{")?;
106124

@@ -118,14 +136,14 @@ impl<N: fmt::Display + Eq + Hash, E> fmt::Debug for Graph<N, E> {
118136
}
119137
}
120138

121-
impl<N: Eq + Hash, E: Eq> PartialEq for Graph<N, E> {
139+
impl<N: Eq + Ord + Clone, E: Eq + Clone> PartialEq for Graph<N, E> {
122140
fn eq(&self, other: &Graph<N, E>) -> bool {
123141
self.nodes.eq(&other.nodes)
124142
}
125143
}
126-
impl<N: Eq + Hash, E: Eq> Eq for Graph<N, E> {}
144+
impl<N: Eq + Ord + Clone, E: Eq + Clone> Eq for Graph<N, E> {}
127145

128-
impl<N: Eq + Hash + Clone, E: Clone> Clone for Graph<N, E> {
146+
impl<N: Eq + Ord + Clone, E: Clone> Clone for Graph<N, E> {
129147
fn clone(&self) -> Graph<N, E> {
130148
Graph {
131149
nodes: self.nodes.clone(),

0 commit comments

Comments
 (0)