From ba339596bfba03b5f607f11a03e2c70ac650f7a7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 19 Mar 2024 11:32:34 +0100 Subject: [PATCH] internal: Delay drawing of workspace dev-dependency edges --- crates/project-model/src/workspace.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 5e06010c67..8b4d6d9941 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -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 // target of downstream. 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 - // 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 - // but in short, such an edge usually causes some form of cycle in the crate graph - // wrt to unit tests. Something we cannot reasonable support. + // but in short, such an edge is able to cause some form of cycle in the crate graph + // 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 && matches!(kind, TargetKind::Lib { .. }) && cargo[dep.pkg].is_member && cargo[pkg].is_member { - tracing::warn!( - "Discarding dev-dependency edge from library target `{}` to library target `{}` to prevent potential cycles", - cargo[dep.pkg].name, - cargo[pkg].name - ); + delayed_dev_deps.push((from, name.clone(), to)); 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 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