Skip to content

Commit 096aad7

Browse files
feat: Improve the diagnostic returned when we can't go, with certainty, from a crate id to the corresponding package id
1 parent 4de8e09 commit 096aad7

1 file changed

Lines changed: 51 additions & 17 deletions

File tree

rustdoc/rustdoc_processor/src/queries/resolution.rs

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,15 @@ pub(crate) fn compute_package_id_for_crate_id(
5151
package_graph: &PackageGraph,
5252
) -> Result<PackageId, anyhow::Error> {
5353
#[derive(Debug, Hash, Eq, PartialEq)]
54-
struct PackageLinkMetadata<'a> {
55-
id: &'a PackageId,
56-
name: &'a str,
57-
version: &'a Version,
54+
struct PackageLinkMetadata {
55+
id: PackageId,
56+
name: String,
57+
version: Version,
58+
}
59+
60+
enum ResolvedDependency {
61+
Found(PackageId),
62+
Ambiguous(IndexSet<PackageLinkMetadata>),
5863
}
5964

6065
/// Find a transitive dependency of `search_root` given its name (and maybe the version).
@@ -66,7 +71,8 @@ pub(crate) fn compute_package_id_for_crate_id(
6671
version: Option<&Version>,
6772
) -> Option<PackageId> {
6873
match _find_transitive_dependency(package_graph, search_root, name, version) {
69-
Ok(v) => v,
74+
Ok(ResolvedDependency::Found(id)) => Some(id),
75+
Ok(ResolvedDependency::Ambiguous(_)) => None,
7076
Err(e) => {
7177
log_error!(
7278
*e,
@@ -86,7 +92,7 @@ pub(crate) fn compute_package_id_for_crate_id(
8692
search_root: &PackageId,
8793
name: &str,
8894
version: Option<&Version>,
89-
) -> Result<Option<PackageId>, anyhow::Error> {
95+
) -> Result<ResolvedDependency, anyhow::Error> {
9096
let transitive_dependencies = package_graph
9197
.query_forward([search_root])
9298
.with_context(|| {
@@ -103,9 +109,9 @@ pub(crate) fn compute_package_id_for_crate_id(
103109
.map(|link| {
104110
let l = link.to();
105111
PackageLinkMetadata {
106-
id: l.id(),
107-
name: l.name(),
108-
version: l.version(),
112+
id: l.id().to_owned(),
113+
name: l.name().to_owned(),
114+
version: l.version().clone(),
109115
}
110116
})
111117
.collect();
@@ -116,14 +122,16 @@ pub(crate) fn compute_package_id_for_crate_id(
116122
)
117123
}
118124
if package_candidates.len() == 1 {
119-
return Ok(Some(package_candidates.first().unwrap().id.to_owned()));
125+
return Ok(ResolvedDependency::Found(
126+
package_candidates.into_iter().next().unwrap().id,
127+
));
120128
}
121129

122130
if let Some(expected_link_version) = version {
123131
let version_matcher = VersionMatcher::new(expected_link_version);
124132
let filtered_candidates: Vec<_> = package_candidates
125133
.iter()
126-
.filter(|l| version_matcher.matches(l.version))
134+
.filter(|l| version_matcher.matches(&l.version))
127135
.collect();
128136
if filtered_candidates.is_empty() {
129137
let candidates = package_candidates
@@ -141,11 +149,13 @@ pub(crate) fn compute_package_id_for_crate_id(
141149
)
142150
}
143151
if filtered_candidates.len() == 1 {
144-
return Ok(Some(filtered_candidates.first().unwrap().id.to_owned()));
152+
return Ok(ResolvedDependency::Found(
153+
filtered_candidates.first().unwrap().id.to_owned(),
154+
));
145155
}
146156
}
147157

148-
Ok(None)
158+
Ok(ResolvedDependency::Ambiguous(package_candidates))
149159
}
150160

151161
if crate_id == 0 {
@@ -163,14 +173,26 @@ pub(crate) fn compute_package_id_for_crate_id(
163173
return Ok(PackageId::new(external_crate.name.clone()));
164174
}
165175
let external_crate_version = get_external_crate_version(external_crate);
166-
if let Some(id) = find_transitive_dependency(
176+
let ambiguous_candidates = match _find_transitive_dependency(
167177
package_graph,
168178
package_id,
169179
&external_crate.name,
170180
external_crate_version.as_ref(),
171181
) {
172-
return Ok(id);
173-
}
182+
Ok(ResolvedDependency::Found(id)) => return Ok(id),
183+
Ok(ResolvedDependency::Ambiguous(candidates)) => Some(candidates),
184+
Err(e) => {
185+
log_error!(
186+
*e,
187+
level: tracing::Level::WARN,
188+
external_crate.name = %external_crate.name,
189+
external_crate.version = ?external_crate_version,
190+
search_root = %package_id.repr(),
191+
"Failed to find transitive dependency"
192+
);
193+
None
194+
}
195+
};
174196

175197
// We have multiple packages with the same name.
176198
// We need to disambiguate among them.
@@ -198,15 +220,27 @@ pub(crate) fn compute_package_id_for_crate_id(
198220
}
199221
}
200222

223+
let candidates_list = ambiguous_candidates
224+
.as_ref()
225+
.map(|candidates| {
226+
let list = candidates
227+
.iter()
228+
.map(|l| format!("- {} v{} ({})", l.name, l.version, l.id.repr()))
229+
.collect::<Vec<_>>()
230+
.join("\n");
231+
format!(":\n{list}\n")
232+
})
233+
.unwrap_or_else(|| ". ".to_owned());
201234
Err(anyhow!(
202-
"There are multiple packages named `{}` among the dependencies of {}. \
235+
"There are multiple packages named `{}` among the dependencies of {}{}\
203236
In order to disambiguate among them, I need to know their versions.\n\
204237
Unfortunately, I couldn't extract the expected version for `{}` from HTML root URL included in the \
205238
JSON documentation for `{}`.\n\
206239
This due to a limitation in `rustdoc` itself: follow https://github.com/rust-lang/compiler-team/issues/622 \
207240
to track progress on this issue.",
208241
external_crate.name,
209242
package_id.repr(),
243+
candidates_list,
210244
external_crate.name,
211245
package_id.repr()
212246
))

0 commit comments

Comments
 (0)