@@ -155,6 +155,10 @@ impl CrateOrigin {
155155 pub fn is_local ( & self ) -> bool {
156156 matches ! ( self , CrateOrigin :: Local { .. } )
157157 }
158+
159+ pub fn is_lib ( & self ) -> bool {
160+ matches ! ( self , CrateOrigin :: Library { .. } )
161+ }
158162}
159163
160164#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
@@ -324,6 +328,62 @@ pub struct CrateData {
324328 pub channel : Option < ReleaseChannel > ,
325329}
326330
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+
327387#[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
328388pub enum Edition {
329389 Edition2015 ,
@@ -351,26 +411,43 @@ impl Env {
351411 }
352412}
353413
414+ #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
415+ pub enum DependencyKind {
416+ Normal ,
417+ Dev ,
418+ Build ,
419+ }
420+
354421#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
355422pub struct Dependency {
356423 pub crate_id : CrateId ,
357424 pub name : CrateName ,
425+ kind : DependencyKind ,
358426 prelude : bool ,
359427}
360428
361429impl 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 }
364432 }
365433
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 }
368441 }
369442
370443 /// Whether this dependency is to be added to the depending crate's extern prelude.
371444 pub fn is_prelude ( & self ) -> bool {
372445 self . prelude
373446 }
447+
448+ pub fn kind ( & self ) -> DependencyKind {
449+ self . kind
450+ }
374451}
375452
376453impl CrateGraph {
@@ -574,23 +651,46 @@ impl CrateGraph {
574651 pub fn extend ( & mut self , mut other : CrateGraph , proc_macros : & mut ProcMacroPaths ) {
575652 let topo = other. crates_in_topological_order ( ) ;
576653 let mut id_map: FxHashMap < CrateId , CrateId > = FxHashMap :: default ( ) ;
577-
578654 for topo in topo {
579655 let crate_data = & mut other. arena [ topo] ;
656+
580657 crate_data. dependencies . iter_mut ( ) . for_each ( |dep| dep. crate_id = id_map[ & dep. crate_id ] ) ;
581658 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+ }
589677 }
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 {
593685 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+ }
594694 } else {
595695 let id = self . arena . alloc ( crate_data. clone ( ) ) ;
596696 id_map. insert ( topo, id) ;
@@ -636,9 +736,11 @@ impl CrateGraph {
636736 match ( cfg_if, std) {
637737 ( Some ( cfg_if) , Some ( std) ) => {
638738 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+ ) ) ;
642744 true
643745 }
644746 _ => false ,
@@ -658,6 +760,8 @@ impl ops::Index<CrateId> for CrateGraph {
658760}
659761
660762impl CrateData {
763+ /// Add a dependency to `self` without checking if the dependency
764+ // is existent among `self.dependencies`.
661765 fn add_dep ( & mut self , dep : Dependency ) {
662766 self . dependencies . push ( dep)
663767 }
@@ -759,7 +863,7 @@ impl fmt::Display for CyclicDependenciesError {
759863
760864#[ cfg( test) ]
761865mod tests {
762- use crate :: CrateOrigin ;
866+ use crate :: { CrateOrigin , DependencyKind } ;
763867
764868 use super :: { CrateGraph , CrateName , Dependency , Edition :: Edition2018 , Env , FileId } ;
765869
@@ -806,13 +910,22 @@ mod tests {
806910 None ,
807911 ) ;
808912 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+ )
810917 . is_ok( ) ) ;
811918 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+ )
813923 . is_ok( ) ) ;
814924 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+ )
816929 . is_err( ) ) ;
817930 }
818931
@@ -846,10 +959,16 @@ mod tests {
846959 None ,
847960 ) ;
848961 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+ )
850966 . is_ok( ) ) ;
851967 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+ )
853972 . is_err( ) ) ;
854973 }
855974
@@ -896,10 +1015,16 @@ mod tests {
8961015 None ,
8971016 ) ;
8981017 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+ )
9001022 . is_ok( ) ) ;
9011023 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+ )
9031028 . is_ok( ) ) ;
9041029 }
9051030
@@ -935,12 +1060,20 @@ mod tests {
9351060 assert ! ( graph
9361061 . add_dep(
9371062 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+ )
9391068 )
9401069 . is_ok( ) ) ;
9411070 assert_eq ! (
9421071 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+ ) ]
9441077 ) ;
9451078 }
9461079}
0 commit comments