@@ -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,35 @@ 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 || version_source. len ( ) == 0 {
423+ return None ;
424+ }
425+ if version_source. len ( ) == 1 {
426+ return Some ( version_source. values ( ) . next ( ) . unwrap ( ) ) ;
427+ }
428+ // If there are multiple candidates for the same name, it needs to be determined by combining versions (See #13405).
429+ if let Ok ( pkg_version) = pkg. version . parse :: < semver:: Version > ( ) {
430+ if let Some ( source_id) = version_source. get ( & pkg_version) {
431+ return Some ( source_id) ;
432+ }
433+ }
434+
435+ None
436+ } )
437+ }
408438 }
409439}
410440
411- fn build_path_deps ( ws : & Workspace < ' _ > ) -> CargoResult < HashMap < String , SourceId > > {
441+ fn build_path_deps (
442+ ws : & Workspace < ' _ > ,
443+ ) -> CargoResult < HashMap < String , HashMap < semver:: Version , SourceId > > > {
412444 // If a crate is **not** a path source, then we're probably in a situation
413445 // such as `cargo install` with a lock file from a remote dependency. In
414446 // that case we don't need to fixup any path dependencies (as they're not
@@ -418,13 +450,15 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
418450 . filter ( |p| p. package_id ( ) . source_id ( ) . is_path ( ) )
419451 . collect :: < Vec < _ > > ( ) ;
420452
421- let mut ret = HashMap :: new ( ) ;
453+ let mut ret: HashMap < String , HashMap < semver :: Version , SourceId > > = HashMap :: new ( ) ;
422454 let mut visited = HashSet :: new ( ) ;
423455 for member in members. iter ( ) {
424- ret. insert (
425- member. package_id ( ) . name ( ) . to_string ( ) ,
426- member. package_id ( ) . source_id ( ) ,
427- ) ;
456+ ret. entry ( member. package_id ( ) . name ( ) . to_string ( ) )
457+ . or_insert_with ( HashMap :: new)
458+ . insert (
459+ member. package_id ( ) . version ( ) . clone ( ) ,
460+ member. package_id ( ) . source_id ( ) ,
461+ ) ;
428462 visited. insert ( member. package_id ( ) . source_id ( ) ) ;
429463 }
430464 for member in members. iter ( ) {
@@ -444,7 +478,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
444478 fn build_pkg (
445479 pkg : & Package ,
446480 ws : & Workspace < ' _ > ,
447- ret : & mut HashMap < String , SourceId > ,
481+ ret : & mut HashMap < String , HashMap < semver :: Version , SourceId > > ,
448482 visited : & mut HashSet < SourceId > ,
449483 ) {
450484 for dep in pkg. dependencies ( ) {
@@ -455,7 +489,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
455489 fn build_dep (
456490 dep : & Dependency ,
457491 ws : & Workspace < ' _ > ,
458- ret : & mut HashMap < String , SourceId > ,
492+ ret : & mut HashMap < String , HashMap < semver :: Version , SourceId > > ,
459493 visited : & mut HashSet < SourceId > ,
460494 ) {
461495 let id = dep. source_id ( ) ;
@@ -467,7 +501,12 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
467501 Err ( _) => return ,
468502 } ;
469503 let Ok ( pkg) = ws. load ( & path) else { return } ;
470- ret. insert ( pkg. name ( ) . to_string ( ) , pkg. package_id ( ) . source_id ( ) ) ;
504+ ret. entry ( pkg. package_id ( ) . name ( ) . to_string ( ) )
505+ . or_insert_with ( HashMap :: new)
506+ . insert (
507+ pkg. package_id ( ) . version ( ) . clone ( ) ,
508+ pkg. package_id ( ) . source_id ( ) ,
509+ ) ;
471510 visited. insert ( pkg. package_id ( ) . source_id ( ) ) ;
472511 build_pkg ( & pkg, ws, ret, visited) ;
473512 }
0 commit comments