@@ -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 ) ]
483495pub 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
488508impl 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