Skip to content

Commit 7db89ed

Browse files
committed
Avoid visiting deps too often in resolve
If we're activating an already-active version of a dependency, then there's no need to actually recurse into it. Instead, we can skip it if we're not enabling any extra features in it to avoid extraneous recursion.
1 parent 82e469e commit 7db89ed

File tree

3 files changed

+33
-29
lines changed

3 files changed

+33
-29
lines changed

src/cargo/core/resolver/mod.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -221,35 +221,47 @@ fn activate_deps<R: Registry>(cx: Context,
221221
log!(5, "{}[{}]>{} trying {}", parent.get_name(), cur, dep.get_name(),
222222
candidate.get_version());
223223
let mut my_cx = cx.clone();
224-
{
224+
let early_return = {
225225
my_cx.resolve.graph.link(parent.get_package_id().clone(),
226226
candidate.get_package_id().clone());
227227
let prev = match my_cx.activations.entry(key.clone()) {
228228
Occupied(e) => e.into_mut(),
229229
Vacant(e) => e.set(Vec::new()),
230230
};
231-
if !prev.iter().any(|c| c == candidate) {
231+
if prev.iter().any(|c| c == candidate) {
232+
match cx.resolve.features(candidate.get_package_id()) {
233+
Some(prev_features) => {
234+
features.iter().all(|f| prev_features.contains(f))
235+
}
236+
None => features.len() == 0,
237+
}
238+
} else {
232239
my_cx.resolve.graph.add(candidate.get_package_id().clone(), []);
233240
prev.push(candidate.clone());
241+
false
234242
}
235-
}
243+
};
236244

237-
// Dependency graphs are required to be a DAG. Non-transitive
238-
// dependencies (dev-deps), however, can never introduce a cycle, so we
239-
// skip them.
240-
if dep.is_transitive() &&
241-
!cx.visited.borrow_mut().insert(candidate.get_package_id().clone()) {
242-
return Err(human(format!("cyclic package dependency: package `{}` \
243-
depends on itself",
244-
candidate.get_package_id())))
245-
}
246-
let my_cx = try!(activate(my_cx, registry, &**candidate, method));
247-
if dep.is_transitive() {
248-
cx.visited.borrow_mut().remove(candidate.get_package_id());
249-
}
250-
let my_cx = match my_cx {
251-
Ok(cx) => cx,
252-
Err(e) => { last_err = Some(e); continue }
245+
let my_cx = if early_return {
246+
my_cx
247+
} else {
248+
// Dependency graphs are required to be a DAG. Non-transitive
249+
// dependencies (dev-deps), however, can never introduce a cycle, so we
250+
// skip them.
251+
if dep.is_transitive() &&
252+
!cx.visited.borrow_mut().insert(candidate.get_package_id().clone()) {
253+
return Err(human(format!("cyclic package dependency: package `{}` \
254+
depends on itself",
255+
candidate.get_package_id())))
256+
}
257+
let my_cx = try!(activate(my_cx, registry, &**candidate, method));
258+
if dep.is_transitive() {
259+
cx.visited.borrow_mut().remove(candidate.get_package_id());
260+
}
261+
match my_cx {
262+
Ok(cx) => cx,
263+
Err(e) => { last_err = Some(e); continue }
264+
}
253265
};
254266
match try!(activate_deps(my_cx, registry, parent, deps, cur + 1)) {
255267
Ok(cx) => return Ok(Ok(cx)),

tests/resolve.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -345,13 +345,7 @@ fn resolving_cycle() {
345345
pkg!("foo" => ["foo"]),
346346
));
347347

348-
let res = resolve(pkg_id("root"), vec![
348+
let _ = resolve(pkg_id("root"), vec![
349349
dep_req("foo", "1"),
350350
], &mut reg);
351-
assert!(res.is_err());
352-
353-
assert_eq!(res.to_string().as_slice(), "Err(\
354-
cyclic package dependency: package `foo v1.0.0 (registry http://example.com/)` \
355-
depends on itself\
356-
)");
357351
}

tests/test_cargo_compile.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,9 +1091,7 @@ test!(self_dependency {
10911091
"#)
10921092
.file("src/test.rs", "fn main() {}");
10931093
assert_that(p.cargo_process("build"),
1094-
execs().with_status(101).with_stderr("\
1095-
cyclic package dependency: package `test v0.0.0 ([..])` depends on itself
1096-
"));
1094+
execs().with_status(0));
10971095
})
10981096

10991097
#[cfg(not(windows))]

0 commit comments

Comments
 (0)