@@ -155,6 +155,10 @@ impl CrateOrigin {
155
155
pub fn is_local ( & self ) -> bool {
156
156
matches ! ( self , CrateOrigin :: Local { .. } )
157
157
}
158
+
159
+ pub fn is_lib ( & self ) -> bool {
160
+ matches ! ( self , CrateOrigin :: Library { .. } )
161
+ }
158
162
}
159
163
160
164
#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
@@ -324,6 +328,62 @@ pub struct CrateData {
324
328
pub channel : Option < ReleaseChannel > ,
325
329
}
326
330
331
+ impl CrateData {
332
+ /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value.
333
+ pub fn eq_ignoring_origin_and_deps ( & self , other : & CrateData , ignore_dev_deps : bool ) -> bool {
334
+ // This method has some obscure bits. These are mostly there to be compliant with
335
+ // some patches. References to the patches are given.
336
+ if self . root_file_id != other. root_file_id {
337
+ return false ;
338
+ }
339
+
340
+ if self . display_name != other. display_name {
341
+ return false ;
342
+ }
343
+
344
+ if self . is_proc_macro != other. is_proc_macro {
345
+ return false ;
346
+ }
347
+
348
+ if self . edition != other. edition {
349
+ return false ;
350
+ }
351
+
352
+ if self . version != other. version {
353
+ return false ;
354
+ }
355
+
356
+ let mut opts = self . cfg_options . difference ( & other. cfg_options ) ;
357
+ if let Some ( it) = opts. next ( ) {
358
+ // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs.
359
+ // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894
360
+ if it. to_string ( ) != "rust_analyzer" {
361
+ return false ;
362
+ }
363
+
364
+ if let Some ( _) = opts. next ( ) {
365
+ return false ;
366
+ }
367
+ }
368
+
369
+ if self . env != other. env {
370
+ return false ;
371
+ }
372
+
373
+ let slf_deps = self . dependencies . iter ( ) ;
374
+ let other_deps = other. dependencies . iter ( ) ;
375
+
376
+ if ignore_dev_deps {
377
+ return slf_deps
378
+ . clone ( )
379
+ . filter ( |it| it. kind != DependencyKind :: Dev )
380
+ . eq ( other_deps. clone ( ) . filter ( |it| it. kind != DependencyKind :: Dev ) ) ;
381
+ }
382
+
383
+ slf_deps. eq ( other_deps)
384
+ }
385
+ }
386
+
327
387
#[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
328
388
pub enum Edition {
329
389
Edition2015 ,
@@ -351,26 +411,43 @@ impl Env {
351
411
}
352
412
}
353
413
414
+ #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
415
+ pub enum DependencyKind {
416
+ Normal ,
417
+ Dev ,
418
+ Build ,
419
+ }
420
+
354
421
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
355
422
pub struct Dependency {
356
423
pub crate_id : CrateId ,
357
424
pub name : CrateName ,
425
+ kind : DependencyKind ,
358
426
prelude : bool ,
359
427
}
360
428
361
429
impl Dependency {
362
- pub fn new ( name : CrateName , crate_id : CrateId ) -> Self {
363
- Self { name, crate_id, prelude : true }
430
+ pub fn new ( name : CrateName , crate_id : CrateId , kind : DependencyKind ) -> Self {
431
+ Self { name, crate_id, prelude : true , kind }
364
432
}
365
433
366
- pub fn with_prelude ( name : CrateName , crate_id : CrateId , prelude : bool ) -> Self {
367
- Self { name, crate_id, prelude }
434
+ pub fn with_prelude (
435
+ name : CrateName ,
436
+ crate_id : CrateId ,
437
+ prelude : bool ,
438
+ kind : DependencyKind ,
439
+ ) -> Self {
440
+ Self { name, crate_id, prelude, kind }
368
441
}
369
442
370
443
/// Whether this dependency is to be added to the depending crate's extern prelude.
371
444
pub fn is_prelude ( & self ) -> bool {
372
445
self . prelude
373
446
}
447
+
448
+ pub fn kind ( & self ) -> DependencyKind {
449
+ self . kind
450
+ }
374
451
}
375
452
376
453
impl CrateGraph {
@@ -574,23 +651,46 @@ impl CrateGraph {
574
651
pub fn extend ( & mut self , mut other : CrateGraph , proc_macros : & mut ProcMacroPaths ) {
575
652
let topo = other. crates_in_topological_order ( ) ;
576
653
let mut id_map: FxHashMap < CrateId , CrateId > = FxHashMap :: default ( ) ;
577
-
578
654
for topo in topo {
579
655
let crate_data = & mut other. arena [ topo] ;
656
+
580
657
crate_data. dependencies . iter_mut ( ) . for_each ( |dep| dep. crate_id = id_map[ & dep. crate_id ] ) ;
581
658
crate_data. dependencies . sort_by_key ( |dep| dep. crate_id ) ;
582
-
583
- let res = self . arena . iter ( ) . find_map (
584
- |( id, data) | {
585
- if data == crate_data {
586
- Some ( id)
587
- } else {
588
- None
659
+ let res = self . arena . iter ( ) . find_map ( |( id, data) | {
660
+ match ( & data. origin , & crate_data. origin ) {
661
+ ( a, b) if a == b => {
662
+ if data. eq_ignoring_origin_and_deps ( & crate_data, false ) {
663
+ return Some ( ( id, false ) ) ;
664
+ }
665
+ }
666
+ ( a @ CrateOrigin :: Local { .. } , CrateOrigin :: Library { .. } )
667
+ | ( a @ CrateOrigin :: Library { .. } , CrateOrigin :: Local { .. } ) => {
668
+ // If the origins differ, check if the two crates are equal without
669
+ // considering the dev dependencies, if they are, they most likely are in
670
+ // different loaded workspaces which may cause issues. We keep the local
671
+ // version and discard the library one as the local version may have
672
+ // dev-dependencies that we want to keep resolving. See #15656 for more
673
+ // information.
674
+ if data. eq_ignoring_origin_and_deps ( & crate_data, true ) {
675
+ return Some ( ( id, if a. is_local ( ) { false } else { true } ) ) ;
676
+ }
589
677
}
590
- } ,
591
- ) ;
592
- if let Some ( res) = res {
678
+ ( _, _) => return None ,
679
+ }
680
+
681
+ None
682
+ } ) ;
683
+
684
+ if let Some ( ( res, should_update_lib_to_local) ) = res {
593
685
id_map. insert ( topo, res) ;
686
+ if should_update_lib_to_local {
687
+ assert ! ( self . arena[ res] . origin. is_lib( ) ) ;
688
+ assert ! ( crate_data. origin. is_local( ) ) ;
689
+ self . arena [ res] . origin = crate_data. origin . clone ( ) ;
690
+
691
+ // Move local's dev dependencies into the newly-local-formerly-lib crate.
692
+ self . arena [ res] . dependencies = crate_data. dependencies . clone ( ) ;
693
+ }
594
694
} else {
595
695
let id = self . arena . alloc ( crate_data. clone ( ) ) ;
596
696
id_map. insert ( topo, id) ;
@@ -636,9 +736,11 @@ impl CrateGraph {
636
736
match ( cfg_if, std) {
637
737
( Some ( cfg_if) , Some ( std) ) => {
638
738
self . arena [ cfg_if] . dependencies . clear ( ) ;
639
- self . arena [ std]
640
- . dependencies
641
- . push ( Dependency :: new ( CrateName :: new ( "cfg_if" ) . unwrap ( ) , cfg_if) ) ;
739
+ self . arena [ std] . dependencies . push ( Dependency :: new (
740
+ CrateName :: new ( "cfg_if" ) . unwrap ( ) ,
741
+ cfg_if,
742
+ DependencyKind :: Normal ,
743
+ ) ) ;
642
744
true
643
745
}
644
746
_ => false ,
@@ -658,6 +760,8 @@ impl ops::Index<CrateId> for CrateGraph {
658
760
}
659
761
660
762
impl CrateData {
763
+ /// Add a dependency to `self` without checking if the dependency
764
+ // is existent among `self.dependencies`.
661
765
fn add_dep ( & mut self , dep : Dependency ) {
662
766
self . dependencies . push ( dep)
663
767
}
@@ -759,7 +863,7 @@ impl fmt::Display for CyclicDependenciesError {
759
863
760
864
#[ cfg( test) ]
761
865
mod tests {
762
- use crate :: CrateOrigin ;
866
+ use crate :: { CrateOrigin , DependencyKind } ;
763
867
764
868
use super :: { CrateGraph , CrateName , Dependency , Edition :: Edition2018 , Env , FileId } ;
765
869
@@ -806,13 +910,22 @@ mod tests {
806
910
None ,
807
911
) ;
808
912
assert ! ( graph
809
- . add_dep( crate1, Dependency :: new( CrateName :: new( "crate2" ) . unwrap( ) , crate2) )
913
+ . add_dep(
914
+ crate1,
915
+ Dependency :: new( CrateName :: new( "crate2" ) . unwrap( ) , crate2, DependencyKind :: Normal )
916
+ )
810
917
. is_ok( ) ) ;
811
918
assert ! ( graph
812
- . add_dep( crate2, Dependency :: new( CrateName :: new( "crate3" ) . unwrap( ) , crate3) )
919
+ . add_dep(
920
+ crate2,
921
+ Dependency :: new( CrateName :: new( "crate3" ) . unwrap( ) , crate3, DependencyKind :: Normal )
922
+ )
813
923
. is_ok( ) ) ;
814
924
assert ! ( graph
815
- . add_dep( crate3, Dependency :: new( CrateName :: new( "crate1" ) . unwrap( ) , crate1) )
925
+ . add_dep(
926
+ crate3,
927
+ Dependency :: new( CrateName :: new( "crate1" ) . unwrap( ) , crate1, DependencyKind :: Normal )
928
+ )
816
929
. is_err( ) ) ;
817
930
}
818
931
@@ -846,10 +959,16 @@ mod tests {
846
959
None ,
847
960
) ;
848
961
assert ! ( graph
849
- . add_dep( crate1, Dependency :: new( CrateName :: new( "crate2" ) . unwrap( ) , crate2) )
962
+ . add_dep(
963
+ crate1,
964
+ Dependency :: new( CrateName :: new( "crate2" ) . unwrap( ) , crate2, DependencyKind :: Normal )
965
+ )
850
966
. is_ok( ) ) ;
851
967
assert ! ( graph
852
- . add_dep( crate2, Dependency :: new( CrateName :: new( "crate2" ) . unwrap( ) , crate2) )
968
+ . add_dep(
969
+ crate2,
970
+ Dependency :: new( CrateName :: new( "crate2" ) . unwrap( ) , crate2, DependencyKind :: Normal )
971
+ )
853
972
. is_err( ) ) ;
854
973
}
855
974
@@ -896,10 +1015,16 @@ mod tests {
896
1015
None ,
897
1016
) ;
898
1017
assert ! ( graph
899
- . add_dep( crate1, Dependency :: new( CrateName :: new( "crate2" ) . unwrap( ) , crate2) )
1018
+ . add_dep(
1019
+ crate1,
1020
+ Dependency :: new( CrateName :: new( "crate2" ) . unwrap( ) , crate2, DependencyKind :: Normal )
1021
+ )
900
1022
. is_ok( ) ) ;
901
1023
assert ! ( graph
902
- . add_dep( crate2, Dependency :: new( CrateName :: new( "crate3" ) . unwrap( ) , crate3) )
1024
+ . add_dep(
1025
+ crate2,
1026
+ Dependency :: new( CrateName :: new( "crate3" ) . unwrap( ) , crate3, DependencyKind :: Normal )
1027
+ )
903
1028
. is_ok( ) ) ;
904
1029
}
905
1030
@@ -935,12 +1060,20 @@ mod tests {
935
1060
assert ! ( graph
936
1061
. add_dep(
937
1062
crate1,
938
- Dependency :: new( CrateName :: normalize_dashes( "crate-name-with-dashes" ) , crate2)
1063
+ Dependency :: new(
1064
+ CrateName :: normalize_dashes( "crate-name-with-dashes" ) ,
1065
+ crate2,
1066
+ DependencyKind :: Normal
1067
+ )
939
1068
)
940
1069
. is_ok( ) ) ;
941
1070
assert_eq ! (
942
1071
graph[ crate1] . dependencies,
943
- vec![ Dependency :: new( CrateName :: new( "crate_name_with_dashes" ) . unwrap( ) , crate2) ]
1072
+ vec![ Dependency :: new(
1073
+ CrateName :: new( "crate_name_with_dashes" ) . unwrap( ) ,
1074
+ crate2,
1075
+ DependencyKind :: Normal
1076
+ ) ]
944
1077
) ;
945
1078
}
946
1079
}
0 commit comments