@@ -1077,6 +1077,8 @@ fn cargo_to_crate_graph(
10771077 }
10781078 }
10791079
1080+ let mut delayed_dev_deps = vec ! [ ] ;
1081+
10801082 // Now add a dep edge from all targets of upstream to the lib
10811083 // target of downstream.
10821084 for pkg in cargo. packages ( ) {
@@ -1092,20 +1094,18 @@ fn cargo_to_crate_graph(
10921094 }
10931095
10941096 // If the dependency is a dev-dependency with both crates being member libraries of
1095- // the workspace we discard the edge. The reason can be read up on in
1097+ // the workspace we delay adding the edge. The reason can be read up on in
10961098 // https://github.com/rust-lang/rust-analyzer/issues/14167
1097- // but in short, such an edge usually causes some form of cycle in the crate graph
1098- // wrt to unit tests. Something we cannot reasonable support.
1099+ // but in short, such an edge is able to cause some form of cycle in the crate graph
1100+ // for normal dependencies. If we do run into a cycle like this, we want to prefer
1101+ // the non dev-dependency edge, and so the easiest way to do that is by adding the
1102+ // dev-dependency edges last.
10991103 if dep. kind == DepKind :: Dev
11001104 && matches ! ( kind, TargetKind :: Lib { .. } )
11011105 && cargo[ dep. pkg ] . is_member
11021106 && cargo[ pkg] . is_member
11031107 {
1104- tracing:: warn!(
1105- "Discarding dev-dependency edge from library target `{}` to library target `{}` to prevent potential cycles" ,
1106- cargo[ dep. pkg] . name,
1107- cargo[ pkg] . name
1108- ) ;
1108+ delayed_dev_deps. push ( ( from, name. clone ( ) , to) ) ;
11091109 continue ;
11101110 }
11111111
@@ -1114,6 +1114,10 @@ fn cargo_to_crate_graph(
11141114 }
11151115 }
11161116
1117+ for ( from, name, to) in delayed_dev_deps {
1118+ add_dep ( crate_graph, from, name, to) ;
1119+ }
1120+
11171121 if has_private {
11181122 // If the user provided a path to rustc sources, we add all the rustc_private crates
11191123 // and create dependencies on them for the crates which opt-in to that
0 commit comments