Skip to content

Commit a5f8bc9

Browse files
committed
Improve resolver message for validate_links
1 parent 0afd40b commit a5f8bc9

File tree

6 files changed

+29
-23
lines changed

6 files changed

+29
-23
lines changed

src/cargo/core/compiler/links.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use super::unit_graph::UnitGraph;
2+
use crate::core::resolver::errors::describe_path;
23
use crate::core::{PackageId, Resolve};
34
use crate::util::errors::CargoResult;
45
use std::collections::{HashMap, HashSet};
5-
use std::fmt::Write;
66

77
/// Validate `links` field does not conflict between packages.
88
pub fn validate_links(resolve: &Resolve, unit_graph: &UnitGraph) -> CargoResult<()> {
@@ -28,17 +28,15 @@ pub fn validate_links(resolve: &Resolve, unit_graph: &UnitGraph) -> CargoResult<
2828
None => continue,
2929
};
3030
if let Some(&prev) = links.get(lib) {
31+
let prev_path = resolve
32+
.path_to_top(&prev)
33+
.into_iter()
34+
.map(|(p, d)| (p, d.and_then(|d| d.iter().next())));
3135
let pkg = unit.pkg.package_id();
32-
33-
let describe_path = |pkgid: PackageId| -> String {
34-
let dep_path = resolve.path_to_top(&pkgid);
35-
let mut dep_path_desc = format!("package `{}`", dep_path[0]);
36-
for dep in dep_path.iter().skip(1) {
37-
write!(dep_path_desc, "\n ... which is depended on by `{}`", dep).unwrap();
38-
}
39-
dep_path_desc
40-
};
41-
36+
let path = resolve
37+
.path_to_top(&pkg)
38+
.into_iter()
39+
.map(|(p, d)| (p, d.and_then(|d| d.iter().next())));
4240
anyhow::bail!(
4341
"multiple packages link to native library `{}`, \
4442
but a native library can be linked only once\n\
@@ -47,9 +45,9 @@ pub fn validate_links(resolve: &Resolve, unit_graph: &UnitGraph) -> CargoResult<
4745
\n\
4846
{}\nalso links to native library `{}`",
4947
lib,
50-
describe_path(prev),
48+
describe_path(prev_path),
5149
lib,
52-
describe_path(pkg),
50+
describe_path(path),
5351
lib
5452
)
5553
}

src/cargo/core/resolver/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ pub(super) fn describe_path_in_context(cx: &Context, id: &PackageId) -> String {
366366
/// -> (pkg1, dep from pkg1 satisfied by pkg0)
367367
/// -> (pkg2, dep from pkg2 satisfied by pkg1)
368368
/// -> ...
369-
pub(super) fn describe_path<'a>(
369+
pub(crate) fn describe_path<'a>(
370370
mut path: impl Iterator<Item = (&'a PackageId, Option<&'a Dependency>)>,
371371
) -> String {
372372
use std::fmt::Write;

src/cargo/core/resolver/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ mod conflict_cache;
7878
mod context;
7979
mod dep_cache;
8080
mod encode;
81-
mod errors;
81+
pub(crate) mod errors;
8282
pub mod features;
8383
mod resolve;
8484
mod types;

src/cargo/core/resolver/resolve.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,10 @@ impl Resolve {
117117

118118
/// Resolves one of the paths from the given dependent package up to
119119
/// the root.
120-
pub fn path_to_top<'a>(&'a self, pkg: &'a PackageId) -> Vec<&'a PackageId> {
120+
pub fn path_to_top<'a>(
121+
&'a self,
122+
pkg: &'a PackageId,
123+
) -> Vec<(&'a PackageId, Option<&'a HashSet<Dependency>>)> {
121124
self.graph.path_to_top(pkg)
122125
}
123126

src/cargo/util/graph.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,23 +111,28 @@ impl<N: Eq + Ord + Clone, E: Default + Clone> Graph<N, E> {
111111

112112
/// Resolves one of the paths from the given dependent package up to
113113
/// the root.
114-
pub fn path_to_top<'a>(&'a self, mut pkg: &'a N) -> Vec<&'a N> {
114+
///
115+
/// Each element contains a node along with an edge except the first one.
116+
/// The representation would look like:
117+
///
118+
/// (Node0,) -> (Node1, Edge01) -> (Node2, Edge12)...
119+
pub fn path_to_top<'a>(&'a self, mut pkg: &'a N) -> Vec<(&'a N, Option<&'a E>)> {
115120
// Note that this implementation isn't the most robust per se, we'll
116121
// likely have to tweak this over time. For now though it works for what
117122
// it's used for!
118-
let mut result = vec![pkg];
119-
let first_pkg_depending_on = |pkg: &N, res: &[&N]| {
123+
let mut result = vec![(pkg, None)];
124+
let first_pkg_depending_on = |pkg, res: &[(&N, Option<&E>)]| {
120125
self.nodes
121126
.iter()
122127
.filter(|(_, adjacent)| adjacent.contains_key(pkg))
123128
// Note that we can have "cycles" introduced through dev-dependency
124129
// edges, so make sure we don't loop infinitely.
125-
.find(|(node, _)| !res.contains(node))
126-
.map(|(p, _)| p)
130+
.find(|&(node, _)| !res.iter().any(|p| p.0 == node))
131+
.map(|(p, adjacent)| (p, adjacent.get(pkg)))
127132
};
128133
while let Some(p) = first_pkg_depending_on(pkg, &result) {
129134
result.push(p);
130-
pkg = p;
135+
pkg = p.0;
131136
}
132137
result
133138
}

tests/testsuite/build_script.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ fn links_duplicates_old_registry() {
10001000
but a native library can be linked only once
10011001
10021002
package `bar v0.1.0`
1003-
... which is depended on by `foo v0.1.0 ([..]foo)`
1003+
... which satisfies dependency `bar = \"=0.1.0\"` of package `foo v0.1.0 ([..]foo)`
10041004
links to native library `a`
10051005
10061006
package `foo v0.1.0 ([..]foo)`

0 commit comments

Comments
 (0)