88
99use std:: { fmt, mem, ops, panic:: RefUnwindSafe , str:: FromStr , sync} ;
1010
11- use cfg:: { CfgDiff , CfgOptions } ;
11+ use cfg:: CfgOptions ;
1212use la_arena:: { Arena , Idx } ;
1313use rustc_hash:: { FxHashMap , FxHashSet } ;
1414use syntax:: SmolStr ;
@@ -330,7 +330,7 @@ pub struct CrateData {
330330
331331impl CrateData {
332332 /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value.
333- pub fn eq_ignoring_origin ( & self , other : & CrateData ) -> bool {
333+ pub fn eq_ignoring_origin_and_deps ( & self , other : & CrateData , ignore_dev_deps : bool ) -> bool {
334334 // This method has some obscure bits. These are mostly there to be compliant with
335335 // some patches. References to the patches are given.
336336 if self . root_file_id != other. root_file_id {
@@ -353,69 +353,36 @@ impl CrateData {
353353 return false ;
354354 }
355355
356- let mut opts = self . cfg_options . clone ( ) ;
357- opts. apply_diff (
358- CfgDiff :: new ( vec ! [ ] , other. cfg_options . clone ( ) . into_iter ( ) . collect ( ) )
359- . expect ( "CfgOptions were expected to contain no duplicates." ) ,
360- ) ;
361-
362- let mut cfgs = opts. into_iter ( ) ;
363- if let Some ( cfg) = cfgs. next ( ) {
364- // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs.
365- // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894
366- if cfgs. next ( ) . is_some ( ) || cfg. to_string ( ) != "rust_analyzer" {
367- return false ;
368- }
369- }
370-
371- let mut itself = self . dependencies . iter ( ) ;
372- let mut otself = other. dependencies . iter ( ) ;
373- let ( mut anx, mut bnx) = ( itself. next ( ) , otself. next ( ) ) ;
374- loop {
375- match ( anx, bnx) {
376- ( None , None ) => {
377- break ;
378- }
379- ( None , Some ( b) ) => {
380- if b. kind != DependencyKind :: Normal {
381- bnx = otself. next ( ) ;
382- } else {
383- break ;
384- }
385- }
386- ( Some ( a) , None ) => {
387- if a. kind != DependencyKind :: Normal {
388- anx = itself. next ( ) ;
389- } else {
390- break ;
391- }
392- }
393- ( Some ( a) , Some ( b) ) => {
394- if a. kind != DependencyKind :: Normal {
395- anx = itself. next ( ) ;
396- continue ;
397- }
398-
399- if b. kind != DependencyKind :: Normal {
400- bnx = otself. next ( ) ;
401- continue ;
402- }
403-
404- if a != b {
356+ let mut opts = self . cfg_options . diff ( & other. cfg_options ) . into_iter ( ) ;
357+ match opts. len ( ) {
358+ 0 => ( ) ,
359+ 1 => {
360+ // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs.
361+ // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894
362+ if let Some ( cfg) = opts. next ( ) {
363+ if cfg. to_string ( ) != "rust_analyzer" {
405364 return false ;
406365 }
407-
408- anx = itself. next ( ) ;
409- bnx = otself. next ( ) ;
410366 }
411367 }
412- }
368+ _ => return false ,
369+ } ;
413370
414371 if self . env != other. env {
415372 return false ;
416373 }
417374
418- true
375+ let slf_deps = self . dependencies . iter ( ) ;
376+ let other_deps = other. dependencies . iter ( ) ;
377+
378+ if ignore_dev_deps {
379+ slf_deps
380+ . clone ( )
381+ . filter ( |it| it. kind == DependencyKind :: Normal )
382+ . eq ( other_deps. clone ( ) . filter ( |it| it. kind == DependencyKind :: Normal ) ) ;
383+ }
384+
385+ slf_deps. eq ( other_deps)
419386 }
420387}
421388
@@ -446,7 +413,7 @@ impl Env {
446413 }
447414}
448415
449- #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
416+ #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
450417pub enum DependencyKind {
451418 Normal ,
452419 Dev ,
@@ -480,8 +447,8 @@ impl Dependency {
480447 self . prelude
481448 }
482449
483- pub fn kind ( & self ) -> & DependencyKind {
484- & self . kind
450+ pub fn kind ( & self ) -> DependencyKind {
451+ self . kind
485452 }
486453}
487454
@@ -692,14 +659,27 @@ impl CrateGraph {
692659 crate_data. dependencies . iter_mut ( ) . for_each ( |dep| dep. crate_id = id_map[ & dep. crate_id ] ) ;
693660 crate_data. dependencies . sort_by_key ( |dep| dep. crate_id ) ;
694661 let res = self . arena . iter ( ) . find_map ( |( id, data) | {
695- if data. eq_ignoring_origin ( crate_data) {
696- if data. origin . is_lib ( ) && crate_data. origin . is_local ( ) {
662+ match ( & data. origin , & crate_data. origin ) {
663+ ( a, b) if a == b => {
664+ if data. eq_ignoring_origin_and_deps ( & crate_data, false ) {
665+ return Some ( ( id, false ) ) ;
666+ }
667+ }
668+ ( CrateOrigin :: Local { .. } , CrateOrigin :: Library { .. } ) => {
697669 // See #15656 for a relevant example.
698- return Some ( ( id, true ) ) ;
670+ if data. eq_ignoring_origin_and_deps ( & crate_data, true ) {
671+ return Some ( ( id, false ) ) ;
672+ }
699673 }
700-
701- return Some ( ( id, false ) ) ;
674+ ( CrateOrigin :: Library { .. } , CrateOrigin :: Local { .. } ) => {
675+ // See #15656 for a relevant example.
676+ if data. eq_ignoring_origin_and_deps ( & crate_data, true ) {
677+ return Some ( ( id, true ) ) ;
678+ }
679+ }
680+ ( _, _) => return None ,
702681 }
682+
703683 None
704684 } ) ;
705685
0 commit comments