99use std:: { fmt, mem, ops, panic:: RefUnwindSafe , str:: FromStr , sync:: Arc } ;
1010
1111use cfg:: CfgOptions ;
12- use la_arena:: { Arena , Idx , RawIdx } ;
12+ use la_arena:: { Arena , Idx } ;
1313use rustc_hash:: { FxHashMap , FxHashSet } ;
1414use syntax:: SmolStr ;
1515use tt:: token_id:: Subtree ;
@@ -534,28 +534,46 @@ impl CrateGraph {
534534 Some ( crate_id)
535535 }
536536
537+ pub fn sort_deps ( & mut self ) {
538+ self . arena
539+ . iter_mut ( )
540+ . for_each ( |( _, data) | data. dependencies . sort_by_key ( |dep| dep. crate_id ) ) ;
541+ }
542+
537543 /// Extends this crate graph by adding a complete disjoint second crate
538544 /// graph and adjust the ids in the [`ProcMacroPaths`] accordingly.
539545 ///
540- /// The ids of the crates in the `other` graph are shifted by the return
541- /// amount.
542- pub fn extend ( & mut self , other : CrateGraph , proc_macros : & mut ProcMacroPaths ) -> u32 {
543- let start = self . arena . len ( ) as u32 ;
544- self . arena . extend ( other. arena . into_iter ( ) . map ( |( _, mut data) | {
545- for dep in & mut data. dependencies {
546- dep. crate_id =
547- CrateId :: from_raw ( RawIdx :: from ( u32:: from ( dep. crate_id . into_raw ( ) ) + start) ) ;
546+ /// This will deduplicate the crates of the graph where possible.
547+ /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id.
548+ /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted.
549+ pub fn extend ( & mut self , mut other : CrateGraph , proc_macros : & mut ProcMacroPaths ) {
550+ let topo = other. crates_in_topological_order ( ) ;
551+ let mut id_map: FxHashMap < CrateId , CrateId > = FxHashMap :: default ( ) ;
552+
553+ for topo in topo {
554+ let crate_data = & mut other. arena [ topo] ;
555+ crate_data. dependencies . iter_mut ( ) . for_each ( |dep| dep. crate_id = id_map[ & dep. crate_id ] ) ;
556+ crate_data. dependencies . sort_by_key ( |dep| dep. crate_id ) ;
557+
558+ let res = self . arena . iter ( ) . find_map (
559+ |( id, data) | {
560+ if data == crate_data {
561+ Some ( id)
562+ } else {
563+ None
564+ }
565+ } ,
566+ ) ;
567+ if let Some ( res) = res {
568+ id_map. insert ( topo, res) ;
569+ } else {
570+ let id = self . arena . alloc ( crate_data. clone ( ) ) ;
571+ id_map. insert ( topo, id) ;
548572 }
549- data
550- } ) ) ;
573+ }
551574
552- * proc_macros = mem:: take ( proc_macros)
553- . into_iter ( )
554- . map ( |( id, macros) | {
555- ( CrateId :: from_raw ( RawIdx :: from ( u32:: from ( id. into_raw ( ) ) + start) ) , macros)
556- } )
557- . collect ( ) ;
558- start
575+ * proc_macros =
576+ mem:: take ( proc_macros) . into_iter ( ) . map ( |( id, macros) | ( id_map[ & id] , macros) ) . collect ( ) ;
559577 }
560578
561579 fn find_path (
@@ -586,8 +604,10 @@ impl CrateGraph {
586604 // Work around for https://github.com/rust-lang/rust-analyzer/issues/6038.
587605 // As hacky as it gets.
588606 pub fn patch_cfg_if ( & mut self ) -> bool {
589- let cfg_if = self . hacky_find_crate ( "cfg_if" ) ;
590- let std = self . hacky_find_crate ( "std" ) ;
607+ // we stupidly max by version in an attempt to have all duplicated std's depend on the same cfg_if so that deduplication still works
608+ let cfg_if =
609+ self . hacky_find_crate ( "cfg_if" ) . max_by_key ( |& it| self . arena [ it] . version . clone ( ) ) ;
610+ let std = self . hacky_find_crate ( "std" ) . next ( ) ;
591611 match ( cfg_if, std) {
592612 ( Some ( cfg_if) , Some ( std) ) => {
593613 self . arena [ cfg_if] . dependencies . clear ( ) ;
@@ -600,8 +620,8 @@ impl CrateGraph {
600620 }
601621 }
602622
603- fn hacky_find_crate ( & self , display_name : & str ) -> Option < CrateId > {
604- self . iter ( ) . find ( |it| self [ * it] . display_name . as_deref ( ) == Some ( display_name) )
623+ fn hacky_find_crate < ' a > ( & ' a self , display_name : & ' a str ) -> impl Iterator < Item = CrateId > + ' a {
624+ self . iter ( ) . filter ( move |it| self [ * it] . display_name . as_deref ( ) == Some ( display_name) )
605625 }
606626}
607627
0 commit comments