@@ -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