@@ -154,7 +154,7 @@ impl EncodableResolve {
154
154
/// primary uses is to be used with `resolve_with_previous` to guide the
155
155
/// resolver to create a complete Resolve.
156
156
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) ?;
158
158
let mut checksums = HashMap :: new ( ) ;
159
159
160
160
let mut version = match self . version {
@@ -202,7 +202,11 @@ impl EncodableResolve {
202
202
if !all_pkgs. insert ( enc_id. clone ( ) ) {
203
203
anyhow:: bail!( "package `{}` is specified twice in the lockfile" , pkg. name) ;
204
204
}
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
+ {
206
210
// We failed to find a local package in the workspace.
207
211
// It must have been removed and should be ignored.
208
212
None => {
@@ -364,7 +368,11 @@ impl EncodableResolve {
364
368
365
369
let mut unused_patches = Vec :: new ( ) ;
366
370
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
+ {
368
376
Some ( & src) => PackageId :: try_new ( & pkg. name , & pkg. version , src) ?,
369
377
None => continue ,
370
378
} ;
@@ -395,7 +403,7 @@ impl EncodableResolve {
395
403
version = ResolveVersion :: V2 ;
396
404
}
397
405
398
- Ok ( Resolve :: new (
406
+ return Ok ( Resolve :: new (
399
407
g,
400
408
replacements,
401
409
HashMap :: new ( ) ,
@@ -404,11 +412,35 @@ impl EncodableResolve {
404
412
unused_patches,
405
413
version,
406
414
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
+ }
408
438
}
409
439
}
410
440
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 > > > {
412
444
// If a crate is **not** a path source, then we're probably in a situation
413
445
// such as `cargo install` with a lock file from a remote dependency. In
414
446
// 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>>
418
450
. filter ( |p| p. package_id ( ) . source_id ( ) . is_path ( ) )
419
451
. collect :: < Vec < _ > > ( ) ;
420
452
421
- let mut ret = HashMap :: new ( ) ;
453
+ let mut ret: HashMap < String , HashMap < semver :: Version , SourceId > > = HashMap :: new ( ) ;
422
454
let mut visited = HashSet :: new ( ) ;
423
455
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
+ ) ;
428
462
visited. insert ( member. package_id ( ) . source_id ( ) ) ;
429
463
}
430
464
for member in members. iter ( ) {
@@ -444,7 +478,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
444
478
fn build_pkg (
445
479
pkg : & Package ,
446
480
ws : & Workspace < ' _ > ,
447
- ret : & mut HashMap < String , SourceId > ,
481
+ ret : & mut HashMap < String , HashMap < semver :: Version , SourceId > > ,
448
482
visited : & mut HashSet < SourceId > ,
449
483
) {
450
484
for dep in pkg. dependencies ( ) {
@@ -455,7 +489,7 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
455
489
fn build_dep (
456
490
dep : & Dependency ,
457
491
ws : & Workspace < ' _ > ,
458
- ret : & mut HashMap < String , SourceId > ,
492
+ ret : & mut HashMap < String , HashMap < semver :: Version , SourceId > > ,
459
493
visited : & mut HashSet < SourceId > ,
460
494
) {
461
495
let id = dep. source_id ( ) ;
@@ -467,7 +501,12 @@ fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>>
467
501
Err ( _) => return ,
468
502
} ;
469
503
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
+ ) ;
471
510
visited. insert ( pkg. package_id ( ) . source_id ( ) ) ;
472
511
build_pkg ( & pkg, ws, ret, visited) ;
473
512
}
0 commit comments