@@ -154,7 +154,7 @@ impl EncodableResolve {
154154 /// primary uses is to be used with `resolve_with_previous` to guide the
155155 /// resolver to create a complete Resolve.
156156 pub fn into_resolve ( self , original : & str , ws : & Workspace < ' _ > ) -> CargoResult < Resolve > {
157- let path_deps = build_path_deps ( ws) ?;
157+ let path_deps: HashMap < String , HashMap < semver :: Version , SourceId > > = build_path_deps ( ws) ?;
158158 let mut checksums = HashMap :: new ( ) ;
159159
160160 let mut version = match self . version {
@@ -202,7 +202,11 @@ impl EncodableResolve {
202202 if !all_pkgs. insert ( enc_id. clone ( ) ) {
203203 anyhow:: bail!( "package `{}` is specified twice in the lockfile" , pkg. name) ;
204204 }
205- let id = match pkg. source . as_deref ( ) . or_else ( || path_deps. get ( & pkg. name ) ) {
205+ let id = match pkg
206+ . source
207+ . as_deref ( )
208+ . or_else ( || get_source_id ( & path_deps, pkg) )
209+ {
206210 // We failed to find a local package in the workspace.
207211 // It must have been removed and should be ignored.
208212 None => {
@@ -364,7 +368,11 @@ impl EncodableResolve {
364368
365369 let mut unused_patches = Vec :: new ( ) ;
366370 for pkg in self . patch . unused {
367- let id = match pkg. source . as_deref ( ) . or_else ( || path_deps. get ( & pkg. name ) ) {
371+ let id = match pkg
372+ . source
373+ . as_deref ( )
374+ . or_else ( || get_source_id ( & path_deps, & pkg) )
375+ {
368376 Some ( & src) => PackageId :: try_new ( & pkg. name , & pkg. version , src) ?,
369377 None => continue ,
370378 } ;
@@ -395,7 +403,7 @@ impl EncodableResolve {
395403 version = ResolveVersion :: V2 ;
396404 }
397405
398- Ok ( Resolve :: new (
406+ return Ok ( Resolve :: new (
399407 g,
400408 replacements,
401409 HashMap :: new ( ) ,
@@ -404,11 +412,34 @@ impl EncodableResolve {
404412 unused_patches,
405413 version,
406414 HashMap :: new ( ) ,
407- ) )
415+ ) ) ;
416+
417+ fn get_source_id < ' a > (
418+ path_deps : & ' a HashMap < String , HashMap < semver:: Version , SourceId > > ,
419+ pkg : & ' a EncodableDependency ,
420+ ) -> Option < & ' a SourceId > {
421+ path_deps. iter ( ) . find_map ( |( name, version_source) | {
422+ if name == & pkg. name {
423+ // If there are multiple candidates for the same name, it needs to be precisely determined by combining versions (See #13405).
424+ if version_source. len ( ) > 1 {
425+ if let Ok ( pkg_version) = pkg. version . parse :: < semver:: Version > ( ) {
426+ if let Some ( source_id) = version_source. get ( & pkg_version) {
427+ return Some ( source_id) ;
428+ }
429+ }
430+ return None ;
431+ }
432+ return Some ( version_source. values ( ) . next ( ) . unwrap ( ) ) ;
433+ }
434+ None
435+ } )
436+ }
408437 }
409438}
410439
411- fn build_path_deps ( ws : & Workspace < ' _ > ) -> CargoResult < HashMap < String , SourceId > > {
440+ fn build_path_deps (
441+ ws : & Workspace < ' _ > ,
442+ ) -> CargoResult < HashMap < String , HashMap < semver:: Version , SourceId > > > {
412443 // If a crate is **not** a path source, then we're probably in a situation
413444 // such as `cargo install` with a lock file from a remote dependency. In
414445 // that case we don't need to fixup any path dependencies (as they're not
@@ -418,13 +449,15 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
418449 . filter ( |p| p. package_id ( ) . source_id ( ) . is_path ( ) )
419450 . collect :: < Vec < _ > > ( ) ;
420451
421- let mut ret = HashMap :: new ( ) ;
452+ let mut ret: HashMap < String , HashMap < semver :: Version , SourceId > > = HashMap :: new ( ) ;
422453 let mut visited = HashSet :: new ( ) ;
423454 for member in members. iter ( ) {
424- ret. insert (
425- member. package_id ( ) . name ( ) . to_string ( ) ,
426- member. package_id ( ) . source_id ( ) ,
427- ) ;
455+ ret. entry ( member. package_id ( ) . name ( ) . to_string ( ) )
456+ . or_insert_with ( HashMap :: new)
457+ . insert (
458+ member. package_id ( ) . version ( ) . clone ( ) ,
459+ member. package_id ( ) . source_id ( ) ,
460+ ) ;
428461 visited. insert ( member. package_id ( ) . source_id ( ) ) ;
429462 }
430463 for member in members. iter ( ) {
@@ -444,7 +477,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
444477 fn build_pkg (
445478 pkg : & Package ,
446479 ws : & Workspace < ' _ > ,
447- ret : & mut HashMap < String , SourceId > ,
480+ ret : & mut HashMap < String , HashMap < semver :: Version , SourceId > > ,
448481 visited : & mut HashSet < SourceId > ,
449482 ) {
450483 for dep in pkg. dependencies ( ) {
@@ -455,7 +488,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
455488 fn build_dep (
456489 dep : & Dependency ,
457490 ws : & Workspace < ' _ > ,
458- ret : & mut HashMap < String , SourceId > ,
491+ ret : & mut HashMap < String , HashMap < semver :: Version , SourceId > > ,
459492 visited : & mut HashSet < SourceId > ,
460493 ) {
461494 let id = dep. source_id ( ) ;
@@ -467,7 +500,12 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
467500 Err ( _) => return ,
468501 } ;
469502 let Ok ( pkg) = ws. load ( & path) else { return } ;
470- ret. insert ( pkg. name ( ) . to_string ( ) , pkg. package_id ( ) . source_id ( ) ) ;
503+ ret. entry ( pkg. package_id ( ) . name ( ) . to_string ( ) )
504+ . or_insert_with ( HashMap :: new)
505+ . insert (
506+ pkg. package_id ( ) . version ( ) . clone ( ) ,
507+ pkg. package_id ( ) . source_id ( ) ,
508+ ) ;
471509 visited. insert ( pkg. package_id ( ) . source_id ( ) ) ;
472510 build_pkg ( & pkg, ws, ret, visited) ;
473511 }
0 commit comments