internal: Delay drawing of workspace dev-dependency edges

This commit is contained in:
Lukas Wirth 2024-03-19 11:32:34 +01:00
parent 4de0204d58
commit ba339596bf

View file

@ -1077,6 +1077,8 @@ fn cargo_to_crate_graph(
} }
} }
let mut delayed_dev_deps = vec![];
// Now add a dep edge from all targets of upstream to the lib // Now add a dep edge from all targets of upstream to the lib
// target of downstream. // target of downstream.
for pkg in cargo.packages() { for pkg in cargo.packages() {
@ -1092,20 +1094,18 @@ fn cargo_to_crate_graph(
} }
// If the dependency is a dev-dependency with both crates being member libraries of // If the dependency is a dev-dependency with both crates being member libraries of
// the workspace we discard the edge. The reason can be read up on in // the workspace we delay adding the edge. The reason can be read up on in
// https://github.com/rust-lang/rust-analyzer/issues/14167 // https://github.com/rust-lang/rust-analyzer/issues/14167
// but in short, such an edge usually causes some form of cycle in the crate graph // but in short, such an edge is able to cause some form of cycle in the crate graph
// wrt to unit tests. Something we cannot reasonable support. // for normal dependencies. If we do run into a cycle like this, we want to prefer
// the non dev-dependency edge, and so the easiest way to do that is by adding the
// dev-dependency edges last.
if dep.kind == DepKind::Dev if dep.kind == DepKind::Dev
&& matches!(kind, TargetKind::Lib { .. }) && matches!(kind, TargetKind::Lib { .. })
&& cargo[dep.pkg].is_member && cargo[dep.pkg].is_member
&& cargo[pkg].is_member && cargo[pkg].is_member
{ {
tracing::warn!( delayed_dev_deps.push((from, name.clone(), to));
"Discarding dev-dependency edge from library target `{}` to library target `{}` to prevent potential cycles",
cargo[dep.pkg].name,
cargo[pkg].name
);
continue; continue;
} }
@ -1114,6 +1114,10 @@ fn cargo_to_crate_graph(
} }
} }
for (from, name, to) in delayed_dev_deps {
add_dep(crate_graph, from, name, to);
}
if has_private { if has_private {
// If the user provided a path to rustc sources, we add all the rustc_private crates // If the user provided a path to rustc sources, we add all the rustc_private crates
// and create dependencies on them for the crates which opt-in to that // and create dependencies on them for the crates which opt-in to that