Skip to content

Commit 5192ddf

Browse files
committed
feat: include full path in the cyclic deps error
1 parent 8d7eea9 commit 5192ddf

File tree

1 file changed

+42
-15
lines changed

1 file changed

+42
-15
lines changed

crates/base_db/src/input.rs

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,17 @@ impl CrateGraph {
247247
to: CrateId,
248248
) -> Result<(), CyclicDependenciesError> {
249249
let _p = profile::span("add_dep");
250-
if self.dfs_find(from, to, &mut FxHashSet::default()) {
251-
return Err(CyclicDependenciesError {
252-
from: (from, self[from].display_name.clone()),
253-
to: (to, self[to].display_name.clone()),
254-
});
250+
251+
// Check if adding a dep from `from` to `to` creates a cycle. To figure
252+
// that out, look for a path in the *opposite* direction, from `to` to
253+
// `from`.
254+
if let Some(path) = self.find_path(&mut FxHashSet::default(), to, from) {
255+
let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect();
256+
let err = CyclicDependenciesError { path };
257+
assert!(err.from().0 == from && err.to().0 == to);
258+
return Err(err);
255259
}
260+
256261
self.arena.get_mut(&from).unwrap().add_dep(name, to);
257262
Ok(())
258263
}
@@ -361,22 +366,29 @@ impl CrateGraph {
361366
start
362367
}
363368

364-
fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool {
369+
fn find_path(
370+
&self,
371+
visited: &mut FxHashSet<CrateId>,
372+
from: CrateId,
373+
to: CrateId,
374+
) -> Option<Vec<CrateId>> {
365375
if !visited.insert(from) {
366-
return false;
376+
return None;
367377
}
368378

369-
if target == from {
370-
return true;
379+
if from == to {
380+
return Some(vec![to]);
371381
}
372382

373383
for dep in &self[from].dependencies {
374384
let crate_id = dep.crate_id;
375-
if self.dfs_find(target, crate_id, visited) {
376-
return true;
385+
if let Some(mut path) = self.find_path(visited, crate_id, to) {
386+
path.push(from);
387+
return Some(path);
377388
}
378389
}
379-
false
390+
391+
None
380392
}
381393

382394
// Work around for https://github.com/rust-analyzer/rust-analyzer/issues/6038.
@@ -481,8 +493,16 @@ impl std::error::Error for ParseEditionError {}
481493

482494
#[derive(Debug)]
483495
pub struct CyclicDependenciesError {
484-
from: (CrateId, Option<CrateDisplayName>),
485-
to: (CrateId, Option<CrateDisplayName>),
496+
path: Vec<(CrateId, Option<CrateDisplayName>)>,
497+
}
498+
499+
impl CyclicDependenciesError {
500+
fn from(&self) -> &(CrateId, Option<CrateDisplayName>) {
501+
self.path.first().unwrap()
502+
}
503+
fn to(&self) -> &(CrateId, Option<CrateDisplayName>) {
504+
self.path.last().unwrap()
505+
}
486506
}
487507

488508
impl fmt::Display for CyclicDependenciesError {
@@ -491,7 +511,14 @@ impl fmt::Display for CyclicDependenciesError {
491511
Some(it) => format!("{}({:?})", it, id),
492512
None => format!("{:?}", id),
493513
};
494-
write!(f, "cyclic deps: {} -> {}", render(&self.from), render(&self.to))
514+
let path = self.path.iter().rev().map(render).collect::<Vec<String>>().join(" -> ");
515+
write!(
516+
f,
517+
"cyclic deps: {} -> {}, alternative path: {}",
518+
render(&self.from()),
519+
render(&self.to()),
520+
path
521+
)
495522
}
496523
}
497524

0 commit comments

Comments
 (0)